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

JuliaLang / julia / #37433

pending completion
#37433

push

local

web-flow
Merge pull request #48513 from JuliaLang/jn/extend-once

ensure extension triggers are only run by the package that satified them

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

72324 of 82360 relevant lines covered (87.81%)

31376331.4 hits per line

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

92.62
/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
7,622,911✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
20,646✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
27,841✔
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,058,042✔
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}
1,446,757✔
76
    @inline
1,445,263✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
1,448,446✔
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)
250,079,891✔
97
    @inline
149,750,356✔
98
    map(oneto, size(A))
5,194,944,273✔
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)...)
1,070,590✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
42,973✔
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...)
729,762✔
115
has_offset_axes(::Colon) = false
8✔
116

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

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

124
!!! compat "Julia 1.2"
125
     This function requires at least Julia 1.2.
126
"""
127
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"))
915,069✔
128

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

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

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

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

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

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

157
julia> keys([4 5; 6 7])
158
CartesianIndices((2, 2))
159
```
160
"""
161
keys(a::AbstractArray) = CartesianIndices(axes(a))
29,068✔
162
keys(a::AbstractVector) = LinearIndices(a)
33,585,259✔
163

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

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

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

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

181
!!! compat "Julia 1.2"
182
     For arrays, this function requires at least Julia 1.2.
183
"""
184
keytype(a::AbstractArray) = keytype(typeof(a))
22,708,142✔
185

186
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
2✔
187
keytype(A::Type{<:AbstractVector}) = Int
22,708,142✔
188

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

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

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

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

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

209
prevind(::AbstractArray, i::Integer) = Int(i)-1
146,460✔
210
nextind(::AbstractArray, i::Integer) = Int(i)+1
171,212,136✔
211

212

213
"""
214
    eltype(type)
215

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

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

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

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

238
"""
239
    elsize(type)
240

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

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

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

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

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

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

264
julia> ndims(A)
265
3
266
```
267
"""
268
ndims(::AbstractArray{T,N}) where {T,N} = N
49,252✔
269
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N
171✔
270

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

274
Return the number of elements in the collection.
275

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

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

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

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

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

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

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

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

304
julia> length([1 2; 3 4])
305
4
306
```
307
"""
308
length(t::AbstractArray) = (@inline; prod(size(t)))
37,277,151✔
309

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

313
# eachindex iterates over all indices. IndexCartesian definitions are later.
314
eachindex(A::AbstractVector) = (@inline(); axes1(A))
863,883,110✔
315

316

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

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

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

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

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

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

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

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

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

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

373
function eachindex(A::AbstractArray, B::AbstractArray)
37✔
374
    @inline
37✔
375
    eachindex(IndexStyle(A,B), A, B)
37✔
376
end
377
function eachindex(A::AbstractArray, B::AbstractArray...)
×
378
    @inline
×
379
    eachindex(IndexStyle(A,B...), A, B...)
×
380
end
381
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
13,848,438✔
382
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
4,192,486,967✔
383
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
34✔
384
    @inline
34✔
385
    indsA = eachindex(IndexLinear(), A)
34✔
386
    _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
72✔
387
        throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
388
    indsA
33✔
389
end
390
function _all_match_first(f::F, inds, A, B...) where F<:Function
42✔
391
    @inline
42✔
392
    (inds == f(A)) & _all_match_first(f, inds, B...)
46✔
393
end
394
_all_match_first(f::F, inds) where F<:Function = true
42✔
395

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

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

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

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

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

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

415
julia> lastindex(rand(3,4,5), 2)
416
4
417
```
418
"""
419
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
1,909,202,099✔
420
lastindex(a, d) = (@inline; last(axes(a, d)))
3,544✔
421

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

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

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

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

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

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

445
first(a::AbstractArray) = a[first(eachindex(a))]
1,081,031✔
446

447
"""
448
    first(coll)
449

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

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

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

460
julia> first([1; 2; 3; 4])
461
1
462
```
463
"""
464
function first(itr)
3,073,679✔
465
    x = iterate(itr)
6,144,094✔
466
    x === nothing && throw(ArgumentError("collection must be non-empty"))
3,073,678✔
467
    x[1]
3,073,676✔
468
end
469

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

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

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

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

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

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

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

502
"""
503
    last(coll)
504

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

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

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

516
julia> last([1; 2; 3; 4])
517
4
518
```
519
"""
520
last(a) = a[end]
23,116,942✔
521

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

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

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

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

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

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

552
"""
553
    strides(A)
554

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

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

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

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

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

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

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

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

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

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

599
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
1,077,277✔
600
size_to_strides(s, d) = (s,)
117✔
601
size_to_strides(s) = ()
×
602

603

604
function isassigned(a::AbstractArray, i::Integer...)
236,781✔
605
    try
236,781✔
606
        a[i...]
357,020✔
607
        true
236,776✔
608
    catch e
609
        if isa(e, BoundsError) || isa(e, UndefRefError)
63✔
610
            return false
33✔
611
        else
612
            rethrow()
1✔
613
        end
614
    end
615
end
616

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

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

643
## Bounds checking ##
644

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

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

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

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

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

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

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

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

682
julia> checkbounds(Bool, A, 1:3, 2:4)
683
false
684
```
685
"""
686
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
98,623,238✔
687
    @inline
98,623,238✔
688
    checkbounds_indices(Bool, axes(A), I)
100,023,016✔
689
end
690

691
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index
692
function checkbounds(::Type{Bool}, A::AbstractArray, i)
124,381,658✔
693
    @inline
118,259,433✔
694
    checkindex(Bool, eachindex(IndexLinear(), A), i)
2,306,329,115✔
695
end
696
# As a special extension, allow using logical arrays that match the source array exactly
697
function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{Bool,N}) where N
88✔
698
    @inline
88✔
699
    axes(A) == axes(I)
143✔
700
end
701

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

705
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
706
"""
707
function checkbounds(A::AbstractArray, I...)
532,267,354✔
708
    @inline
214,207,428✔
709
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
532,268,377✔
710
    nothing
532,267,742✔
711
end
712

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

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

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

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

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

731
See also [`checkbounds`](@ref).
732
"""
733
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
214,435,202✔
734
    @inline
13,770,438✔
735
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
384,669,834✔
736
end
737
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
22,116✔
738
    @inline
3,419✔
739
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
34,283✔
740
end
741
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
577,874✔
742
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
×
743

744
throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I)))
717✔
745

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

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

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

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

762
julia> checkindex(Bool, 1:20, 21)
763
false
764
```
765
"""
766
checkindex(::Type{Bool}, inds::AbstractUnitRange, i) =
×
767
    throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
768
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
2,968,683,982✔
769
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
285✔
770
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
125✔
771
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
7,892,689✔
772
    @_propagate_inbounds_meta
472,302✔
773
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
271,404,180✔
774
end
775
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == axes1(I)
2✔
776
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool}) = false
1✔
777
function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
14,434✔
778
    @inline
9,139✔
779
    b = true
9,139✔
780
    for i in I
24,054✔
781
        b &= checkindex(Bool, inds, i)
17,551,556✔
782
    end
28,724,282✔
783
    b
17,463✔
784
end
785

786
# See also specializations in multidimensional
787

788
## Constructors ##
789

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

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

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

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

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

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

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

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

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

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

849
to_shape(::Tuple{}) = ()
400✔
850
to_shape(dims::Dims) = dims
6,049✔
851
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
5,254,820✔
852
# each dimension
853
to_shape(i::Int) = i
3✔
854
to_shape(i::Integer) = Int(i)
83✔
855
to_shape(r::OneTo) = Int(last(r))
64,932✔
856
to_shape(r::AbstractUnitRange) = r
196✔
857

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

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

865
**Examples**:
866

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

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

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

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

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

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

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

891
# Examples
892

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

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

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

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

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

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

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

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

937
## from general iterable to any array
938

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

943
function copyto!(dest::AbstractArray, src)
20,343,094✔
944
    destiter = eachindex(dest)
20,343,152✔
945
    y = iterate(destiter)
26,452,656✔
946
    for x in src
27,533,570✔
947
        y === nothing &&
10,441,351✔
948
            throw(ArgumentError("destination has fewer elements than required"))
949
        dest[y[1]] = x
10,441,470✔
950
        y = iterate(destiter, y[2])
14,772,923✔
951
    end
14,252,966✔
952
    return dest
20,343,150✔
953
end
954

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

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

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

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

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

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

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

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

1049
julia> y = zeros(7);
1050

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

1053
julia> y
1054
7-element Vector{Float64}:
1055
 1.0
1056
 0.0
1057
 3.0
1058
 0.0
1059
 5.0
1060
 0.0
1061
 0.0
1062
```
1063
"""
1064
function copyto!(dest::AbstractArray, src::AbstractArray)
2,626,184✔
1065
    isempty(src) && return dest
2,629,518✔
1066
    if dest isa BitArray
150,882✔
1067
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1068
        return _copyto_bitarray!(dest, src)
1✔
1069
    end
1070
    src′ = unalias(dest, src)
2,666,477✔
1071
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,629,040✔
1072
end
1073

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

1080
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
2,626,889✔
1081
    isempty(src) && return dest
2,629,040✔
1082
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,629,041✔
1083
    idf, isf = first(destinds), first(srcinds)
150,877✔
1084
    Δi = idf - isf
150,877✔
1085
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,629,041✔
1086
        throw(BoundsError(dest, srcinds))
1087
    if deststyle isa IndexLinear
150,876✔
1088
        if srcstyle isa IndexLinear
146,584✔
1089
            # Single-index implementation
1090
            @inbounds for i in srcinds
4,976,220✔
1091
                dest[i + Δi] = src[i]
17,600,792✔
1092
            end
32,704,640✔
1093
        else
1094
            # Dual-index implementation
1095
            i = idf - 1
136,228✔
1096
            @inbounds for a in src
272,280✔
1097
                dest[i+=1] = a
4,786,527✔
1098
            end
9,429,049✔
1099
        end
1100
    else
1101
        iterdest, itersrc = eachindex(dest), eachindex(src)
4,292✔
1102
        if iterdest == itersrc
4,292✔
1103
            # Shared-iterator implementation
1104
            for I in iterdest
4,146✔
1105
                @inbounds dest[I] = src[I]
6,384,660✔
1106
            end
12,201,213✔
1107
        else
1108
            # Dual-iterator implementation
1109
            ret = iterate(iterdest)
4,438✔
1110
            @inbounds for a in src
4,264✔
1111
                idx, state = ret::NTuple{2,Any}
2,002,243✔
1112
                dest[idx] = a
2,002,243✔
1113
                ret = iterate(iterdest, state)
2,004,463✔
1114
            end
4,000,749✔
1115
        end
1116
    end
1117
    return dest
2,629,039✔
1118
end
1119

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

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

1130
function copyto!(dest::AbstractArray, dstart::Integer,
31,543✔
1131
               src::AbstractArray, sstart::Integer,
1132
               n::Integer)
1133
    n == 0 && return dest
31,543✔
1134
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
31,541✔
1135
        n," elements, but n should be nonnegative")))
1136
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
31,540✔
1137
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
31,552✔
1138
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
31,531✔
1139
    src′ = unalias(dest, src)
33,688✔
1140
    @inbounds for i = 0:n-1
63,050✔
1141
        dest[dstart+i] = src′[sstart+i]
1,312,389✔
1142
    end
2,593,253✔
1143
    return dest
31,525✔
1144
end
1145

1146
function copy(a::AbstractArray)
146,957✔
1147
    @_propagate_inbounds_meta
579✔
1148
    copymutable(a)
147,157✔
1149
end
1150

1151
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
8,007✔
1152
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1153
    if length(ir_dest) != length(ir_src)
8,007✔
1154
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1155
            length(ir_src)," and ",length(ir_dest),")")))
1156
    end
1157
    if length(jr_dest) != length(jr_src)
8,006✔
1158
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1159
            length(jr_src)," and ",length(jr_dest),")")))
1160
    end
1161
    @boundscheck checkbounds(B, ir_dest, jr_dest)
8,006✔
1162
    @boundscheck checkbounds(A, ir_src, jr_src)
8,006✔
1163
    A′ = unalias(B, A)
16,003✔
1164
    jdest = first(jr_dest)
8,006✔
1165
    for jsrc in jr_src
16,012✔
1166
        idest = first(ir_dest)
23,362✔
1167
        for isrc in ir_src
46,724✔
1168
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
137,921✔
1169
            idest += step(ir_dest)
137,278✔
1170
        end
251,194✔
1171
        jdest += step(jr_dest)
23,362✔
1172
    end
38,718✔
1173
    return B
8,006✔
1174
end
1175

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

1178
function copyto_axcheck!(dest, src)
45,876✔
1179
    _checkaxs(axes(dest), axes(src))
51,911✔
1180
    copyto!(dest, src)
63,191✔
1181
end
1182

1183
"""
1184
    copymutable(a)
1185

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

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

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

1209
zero(x::AbstractArray{T}) where {T} = fill!(similar(x, typeof(zero(T))), zero(T))
15,988✔
1210

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

1214
# While the definitions for IndexLinear are all simple enough to inline on their
1215
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1216
# inlining.
1217
function iterate(A::AbstractArray, state=(eachindex(A),))
67,552,787✔
1218
    y = iterate(state...)
77,544,988✔
1219
    y === nothing && return nothing
68,221,569✔
1220
    A[y[1]], (state[1], tail(y)...)
67,781,871✔
1221
end
1222

1223
isempty(a::AbstractArray) = (length(a) == 0)
2,338,068,145✔
1224

1225

1226
## range conversions ##
1227

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

1235
## unsafe/pointer conversions ##
1236

1237
# note: the following type definitions don't mean any AbstractArray is convertible to
1238
# a data Ref. they just map the array element type to the pointer type for
1239
# convenience in cases that work.
1240
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
17,192,659✔
1241
function pointer(x::AbstractArray{T}, i::Integer) where T
8,556,626✔
1242
    @inline
5,050,061✔
1243
    unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
258,803,183✔
1244
end
1245

1246
# The distance from pointer(x) to the element at x[I...] in bytes
1247
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
223,160,875✔
1248
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
100,368✔
1249
    J = _to_subscript_indices(x, I...)
100,368✔
1250
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
376,777✔
1251
end
1252

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

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

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

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

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

1284
julia> getindex(A, 2:4)
1285
3-element Vector{Int64}:
1286
 3
1287
 2
1288
 4
1289
```
1290
"""
1291
function getindex(A::AbstractArray, I...)
98,399,026✔
1292
    @_propagate_inbounds_meta
98,052,629✔
1293
    error_if_canonical_getindex(IndexStyle(A), A, I...)
98,052,629✔
1294
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
214,470,673✔
1295
end
1296
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1297
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
152,565,542✔
1298

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

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

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

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

1321
## IndexLinear Scalar indexing: canonical method is one Int
1322
_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)
387,788✔
1323
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
51✔
1324
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
2,747,164✔
1325
    @inline
1,663,308✔
1326
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
30,968,713✔
1327
    @inbounds r = getindex(A, _to_linear_index(A, I...))
30,968,656✔
1328
    r
30,968,627✔
1329
end
1330
_to_linear_index(A::AbstractArray, i::Integer) = i
231,773✔
1331
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1,720,065✔
1332
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
323,580✔
1333
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
2,865,433✔
1334

1335
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1336
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
313,569✔
1337
    @inline
313,569✔
1338
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
313,642✔
1339
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
321,229✔
1340
    r
313,495✔
1341
end
1342
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
94,815,098✔
1343
    @_propagate_inbounds_meta
94,815,098✔
1344
    getindex(A, I...)
182,399,781✔
1345
end
1346
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
387,927✔
1347
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1348
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1349
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
416✔
1350
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1351
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1,820✔
1352
    @inline
1,820✔
1353
    J, Jrem = IteratorsMD.split(I, Val(N))
1,820✔
1354
    _to_subscript_indices(A, J, Jrem)
1,820✔
1355
end
1356
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1357
    __to_subscript_indices(A, axes(A), J, Jrem)
1358
function __to_subscript_indices(A::AbstractArray,
2✔
1359
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1360
    @inline
2✔
1361
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1362
end
1363
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
1,818✔
1364
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
29,276✔
1365
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1366
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1367
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1368
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
387,927✔
1369

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

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

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

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

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

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

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

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

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

1415
## IndexLinear Scalar indexing
1416
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
222,765✔
1417
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
161,754✔
1418
    @inline
107,203✔
1419
    @boundscheck checkbounds(A, I...)
164,681✔
1420
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
164,644✔
1421
    r
164,643✔
1422
end
1423

1424
# IndexCartesian Scalar indexing
1425
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,364,717✔
1426
    @_propagate_inbounds_meta
2,364,717✔
1427
    setindex!(A, v, I...)
2,364,814✔
1428
end
1429
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
2,832✔
1430
    @inline
2,832✔
1431
    @boundscheck checkbounds(A, I...)
2,837✔
1432
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
2,827✔
1433
    r
2,827✔
1434
end
1435

1436
"""
1437
    parent(A)
1438

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

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

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

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

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

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

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

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

1478
See also [`Base.mightalias`](@ref).
1479
"""
1480
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
8,186,995✔
1481
unalias(dest, A::AbstractRange) = A
2,809,487✔
1482
unalias(dest, A) = A
2,608,834✔
1483

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

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

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

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

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

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

1518
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1519
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1520
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1521
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1522
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
5,280,124✔
1523
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
85,700✔
1524
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1525
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
5,858✔
1526
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
83,866✔
1527

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

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

1533
Custom arrays that would like to opt-in to aliasing detection of their component
1534
parts can specialize this method to return the concatenation of the `dataids` of
1535
their component parts.  A typical definition for an array that wraps a parent is
1536
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1537
"""
1538
dataids(A::AbstractArray) = (UInt(objectid(A)),)
109,064✔
1539
dataids(A::Array) = (UInt(pointer(A)),)
10,578,154✔
1540
dataids(::AbstractRange) = ()
19,656✔
1541
dataids(x) = ()
6,906✔
1542

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

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

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

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

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

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

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

1585
## structured matrix methods ##
1586
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
47,954✔
1587
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
5,186✔
1588

1589
## Concatenation ##
1590
eltypeof(x) = typeof(x)
21,623✔
1591
eltypeof(x::AbstractArray) = eltype(x)
13,253✔
1592

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

1596
promote_eltype() = Bottom
3,158✔
1597
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
13,596✔
1598

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

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

1605
## cat: special cases
1606
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
312✔
1607
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
293✔
1608
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
93✔
1609
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
504✔
1610

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

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

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

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

1628
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
793,202✔
1629
    pos = 1
793,202✔
1630
    for k=1:Int(length(V))::Int
793,207✔
1631
        Vk = V[k]
794,903✔
1632
        p1 = pos + Int(length(Vk))::Int - 1
795,498✔
1633
        a[pos:p1] = Vk
5,721,066✔
1634
        pos = p1+1
794,903✔
1635
    end
796,604✔
1636
    a
793,202✔
1637
end
1638

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

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

1644
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
529✔
1645
    nargs = length(A)
529✔
1646
    nrows = size(A[1], 1)
529✔
1647
    ncols = 0
529✔
1648
    dense = true
529✔
1649
    for j = 1:nargs
535✔
1650
        Aj = A[j]
1,093✔
1651
        if size(Aj, 1) != nrows
1,324✔
1652
            throw(ArgumentError("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
7✔
1653
        end
1654
        dense &= isa(Aj,Array)
1,092✔
1655
        nd = ndims(Aj)
1,191✔
1656
        ncols += (nd==2 ? size(Aj,2) : 1)
1,261✔
1657
    end
1,656✔
1658
    B = similar(A[1], T, nrows, ncols)
528✔
1659
    pos = 1
528✔
1660
    if dense
528✔
1661
        for k=1:nargs
408✔
1662
            Ak = A[k]
839✔
1663
            n = length(Ak)
969✔
1664
            copyto!(B, pos, Ak, 1, n)
981✔
1665
            pos += n
839✔
1666
        end
1,272✔
1667
    else
1668
        for k=1:nargs
126✔
1669
            Ak = A[k]
252✔
1670
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
309✔
1671
            B[:, pos:p1] = Ak
252✔
1672
            pos = p1+1
252✔
1673
        end
252✔
1674
    end
1675
    return B
528✔
1676
end
1677

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

1681
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
785✔
1682
    nargs = length(A)
785✔
1683
    nrows = sum(a->size(a, 1), A)::Int
2,460✔
1684
    ncols = size(A[1], 2)
785✔
1685
    for j = 2:nargs
786✔
1686
        if size(A[j], 2) != ncols
844✔
1687
            throw(ArgumentError("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
5✔
1688
        end
1689
    end
904✔
1690
    B = similar(A[1], T, nrows, ncols)
784✔
1691
    pos = 1
784✔
1692
    for k=1:nargs
785✔
1693
        Ak = A[k]
1,620✔
1694
        p1 = pos+size(Ak,1)::Int-1
1,707✔
1695
        B[pos:p1, :] = Ak
1,620✔
1696
        pos = p1+1
1,620✔
1697
    end
2,456✔
1698
    return B
784✔
1699
end
1700

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

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

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

1709
## cat: general case
1710

1711
# helper functions
1712
cat_size(A) = (1,)
22,283✔
1713
cat_size(A::AbstractArray) = size(A)
16,874✔
1714
cat_size(A, d) = 1
22,633✔
1715
cat_size(A::AbstractArray, d) = size(A, d)
24,627✔
1716

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

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

1723
cat_indices(A, d) = OneTo(1)
22,278✔
1724
cat_indices(A::AbstractArray, d) = axes(A, d)
18,030✔
1725

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

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

1748
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1749
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
20✔
1750
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
492✔
1751
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
636✔
1752
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1753
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
3,477✔
1754
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1755
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
25✔
1756
    _cs(ndim, shape[1], 1)
27✔
1757
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
23✔
1758
end
1759
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
252✔
1760
    next = _cs(ndim, shape[1], nshape[1])
252✔
1761
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
252✔
1762
end
1763
@inline function _cshp(ndim::Int, dims, shape, nshape)
30,973✔
1764
    a = shape[1]
30,973✔
1765
    b = nshape[1]
30,973✔
1766
    next = dims[1] ? a + b : _cs(ndim, a, b)
31,891✔
1767
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
31,003✔
1768
end
1769

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

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

1781
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
7,289✔
1782

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

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

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

1806
function __cat_offset1!(A, shape, catdims, offsets, x)
39,136✔
1807
    inds = ntuple(length(offsets)) do i
39,259✔
1808
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
43,423✔
1809
    end
1810
    if x isa AbstractArray
39,136✔
1811
        A[inds...] = x
107,131✔
1812
    else
1813
        fill!(view(A, inds...), x)
23,081✔
1814
    end
1815
    newoffsets = ntuple(length(offsets)) do i
39,137✔
1816
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
45,536✔
1817
    end
1818
    return newoffsets
39,135✔
1819
end
1820

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1999
# 2d horizontal and vertical concatenation
2000

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2105
    a = Matrix{T}(undef, nr, nc)
1,177✔
2106
    if length(a) != length(xs)
1,177✔
2107
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2108
    end
2109
    k = 1
461✔
2110
    @inbounds for i=1:nr
1,175✔
2111
        if nc != rows[i]
3,235✔
2112
            throw(ArgumentError("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2113
        end
2114
        for j=1:nc
6,468✔
2115
            a[i,j] = xs[k]
9,009✔
2116
            k += 1
9,009✔
2117
        end
14,784✔
2118
    end
5,294✔
2119
    a
1,174✔
2120
end
2121

2122
function hvcat_fill!(a::Array, xs::Tuple)
401✔
2123
    nr, nc = size(a,1), size(a,2)
401✔
2124
    len = length(xs)
401✔
2125
    if nr*nc != len
401✔
2126
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2127
    end
2128
    k = 1
400✔
2129
    for i=1:nr
800✔
2130
        @inbounds for j=1:nc
2,214✔
2131
            a[i,j] = xs[k]
8,818✔
2132
            k += 1
8,191✔
2133
        end
15,275✔
2134
    end
1,814✔
2135
    a
400✔
2136
end
2137

2138
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
145✔
2139
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
128✔
2140

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

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

2163
## N-dimensional concatenation ##
2164

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2260

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

2264
# 1-dimensional hvncat methods
2265

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

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

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

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

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

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

2307
    nd = N
17✔
2308

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

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

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

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

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

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

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

2366

2367
# balanced dimensions hvncat methods
2368

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

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

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

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

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

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

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

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

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

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

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

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

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

2512

2513
# unbalanced dimensions hvncat methods
2514

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2703
Higher-dimensional examples:
2704

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2804
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
8,777✔
2805
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
37✔
2806
_iterator_axes(x, ::IteratorSize) = axes(x)
8,740✔
2807

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

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

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

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

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

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

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

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

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

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

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

2875

2876
## Reductions and accumulates ##
2877

2878
function isequal(A::AbstractArray, B::AbstractArray)
247,251✔
2879
    if A === B return true end
247,510✔
2880
    if axes(A) != axes(B)
490,487✔
2881
        return false
3,479✔
2882
    end
2883
    for (a, b) in zip(A, B)
486,424✔
2884
        if !isequal(a, b)
91,274,352✔
2885
            return false
567✔
2886
        end
2887
    end
182,100,602✔
2888
    return true
242,946✔
2889
end
2890

2891
function cmp(A::AbstractVector, B::AbstractVector)
315✔
2892
    for (a, b) in zip(A, B)
630✔
2893
        if !isequal(a, b)
880✔
2894
            return isless(a, b) ? -1 : 1
311✔
2895
        end
2896
    end
1,145✔
2897
    return cmp(length(A), length(B))
15✔
2898
end
2899

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

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

2907
function (==)(A::AbstractArray, B::AbstractArray)
6,561,199✔
2908
    if axes(A) != axes(B)
13,122,353✔
2909
        return false
2,847✔
2910
    end
2911
    anymissing = false
6,554,671✔
2912
    for (a, b) in zip(A, B)
12,232,890✔
2913
        eq = (a == b)
340,475,198✔
2914
        if ismissing(eq)
305,827,824✔
2915
            anymissing = true
21✔
2916
        elseif !eq
339,586,858✔
2917
            return false
2,360✔
2918
        end
2919
    end
673,498,251✔
2920
    return anymissing ? missing : true
6,557,433✔
2921
end
2922

2923
# _sub2ind and _ind2sub
2924
# fallbacks
2925
function _sub2ind(A::AbstractArray, I...)
1,496,699✔
2926
    @inline
1,496,699✔
2927
    _sub2ind(axes(A), I...)
2,865,433✔
2928
end
2929

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

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

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

2951
_sub2ind_recurse(::Any, L, ind) = ind
2,303,406✔
2952
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,804✔
2953
    @inline
867✔
2954
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
12,157✔
2955
end
2956
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
3,674,726✔
2957
    @inline
3,100,406✔
2958
    r1 = inds[1]
3,692,576✔
2959
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
1,936,449,051✔
2960
end
2961

2962
nextL(L, l::Integer) = L*l
2,450,157✔
2963
nextL(L, r::AbstractUnitRange) = L*length(r)
3,520,654✔
2964
nextL(L, r::Slice) = L*length(r.indices)
×
2965
offsetin(i, l::Integer) = i-1
1,929,917,930✔
2966
offsetin(i, r::AbstractUnitRange) = i-first(r)
6,493,322✔
2967

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

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

2987
_lookup(ind, d::Integer) = ind+1
2,053✔
2988
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
387,913✔
2989
_div(ind, d::Integer) = div(ind, d), 1, d
2,053✔
2990
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
1,468,084✔
2991

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

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

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

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

3036
## iteration utilities ##
3037

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

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

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

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

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

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

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

3070
## map over arrays ##
3071

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3240
## 0 arguments
3241

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

3244
## 1 argument
3245

3246
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,757✔
3247
    for (i,j) in zip(eachindex(dest),eachindex(A))
223,352,265✔
3248
        val = f(@inbounds A[j])
223,956,540✔
3249
        @inbounds dest[i] = val
133,608,541✔
3250
    end
164,660,645✔
3251
    return dest
120,998,070✔
3252
end
3253

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

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

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

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

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

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

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

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

3288
## 2 argument
3289
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
376✔
3290
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
739✔
3291
        @inbounds a, b = A[j], B[k]
387,574✔
3292
        val = f(a, b)
338,252✔
3293
        @inbounds dest[i] = val
338,252✔
3294
    end
676,141✔
3295
    return dest
376✔
3296
end
3297

3298
## N argument
3299

3300
@inline ith_all(i, ::Tuple{}) = ()
4,030✔
3301
function ith_all(i, as)
12,090✔
3302
    @_propagate_inbounds_meta
12,090✔
3303
    return (as[1][i], ith_all(i, tail(as))...)
18,930✔
3304
end
3305

3306
function map_n!(f::F, dest::AbstractArray, As) where F
46✔
3307
    idxs1 = LinearIndices(As[1])
46✔
3308
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
368✔
3309
    for i = idxs1
92✔
3310
        @inbounds I = ith_all(i, As)
6,550✔
3311
        val = f(I...)
4,030✔
3312
        @inbounds dest[i] = val
4,030✔
3313
    end
8,014✔
3314
    return dest
46✔
3315
end
3316

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3386
## hashing AbstractArray ##
3387

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

3396
    # For short arrays, it's not worth doing anything complicated
3397
    if length(A) < 8192
14,653✔
3398
        for x in A
18,925✔
3399
            h = hash(x, h)
562,534✔
3400
        end
696,244✔
3401
        return h
14,412✔
3402
    end
3403

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

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

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

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

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

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

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

3458
    return h
4✔
3459
end
3460

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

3469

3470
## keepat! ##
3471

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

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

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

3506
## 1-d circshift ##
3507
function circshift!(a::AbstractVector, shift::Integer)
1,137✔
3508
    n = length(a)
1,137✔
3509
    n == 0 && return
1,137✔
3510
    shift = mod(shift, n)
2,274✔
3511
    shift == 0 && return
1,137✔
3512
    l = lastindex(a)
731✔
3513
    reverse!(a, firstindex(a), l-shift)
731✔
3514
    reverse!(a, l-shift+1, lastindex(a))
731✔
3515
    reverse!(a)
731✔
3516
    return a
731✔
3517
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc