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

JuliaLang / julia / #37527

pending completion
#37527

push

local

web-flow
make `IRShow.method_name` inferrable (#49607)

18 of 18 new or added lines in 3 files covered. (100.0%)

68710 of 81829 relevant lines covered (83.97%)

33068903.12 hits per line

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

92.01
/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
73,970✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
20,622✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
27,787✔
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,611,593✔
43

44
"""
45
    axes(A, d)
46

47
Return the valid range of indices for array `A` along dimension `d`.
48

49
See also [`size`](@ref), and the manual chapter on [arrays with custom indices](@ref man-custom-indices).
50

51
# Examples
52

53
```jldoctest
54
julia> A = fill(1, (5,6,7));
55

56
julia> axes(A, 2)
57
Base.OneTo(6)
58

59
julia> axes(A, 4) == 1:1  # all dimensions d > ndims(A) have size 1
60
true
61
```
62

63
# Usage note
64

65
Each of the indices has to be an `AbstractUnitRange{<:Integer}`, but at the same time can be
66
a type that uses custom indices. So, for example, if you need a subset, use generalized
67
indexing constructs like `begin`/`end` or [`firstindex`](@ref)/[`lastindex`](@ref):
68

69
```julia
70
ix = axes(v, 1)
71
ix[2:end]          # will work for eg Vector, but may fail in general
72
ix[(begin+1):end]  # works for generalized indexes
73
```
74
"""
75
function axes(A::AbstractArray{T,N}, d) where {T,N}
800,491✔
76
    @inline
799,115✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
805,290✔
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)
207,369,035✔
97
    @inline
107,678,594✔
98
    map(oneto, size(A))
4,532,878,506✔
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)...)
640,992✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
59,195✔
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...)
266,602✔
115
has_offset_axes(::Colon) = false
67✔
116
has_offset_axes(::Array) = false
580,577✔
117

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

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

125
!!! compat "Julia 1.2"
126
     This function requires at least Julia 1.2.
127
"""
128
require_one_based_indexing(A...) = !has_offset_axes(A...) || throw(ArgumentError("offset arrays are not supported but got an array with index other than 1"))
1,365,319✔
129

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

212
prevind(::AbstractArray, i::Integer) = Int(i)-1
4,131✔
213
nextind(::AbstractArray, i::Integer) = Int(i)+1
171,311,054✔
214

215

216
"""
217
    eltype(type)
218

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

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

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

232
julia> eltype(fill(0x1, (2,2)))
233
UInt8
234
```
235
"""
236
eltype(::Type) = Any
1,457✔
237
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
4✔
238
eltype(x) = eltype(typeof(x))
4,612,925✔
239
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
2,565,704✔
240

241
"""
242
    elsize(type)
243

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

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

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

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

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

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

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

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

278
Return the number of elements in the collection.
279

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

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

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

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

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

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

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

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

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

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

317
# eachindex iterates over all indices. IndexCartesian definitions are later.
318
eachindex(A::AbstractVector) = (@inline(); axes1(A))
849,176,955✔
319

320

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

449
first(a::AbstractArray) = a[first(eachindex(a))]
201,525✔
450

451
"""
452
    first(coll)
453

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

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

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

464
julia> first([1; 2; 3; 4])
465
1
466
```
467
"""
468
function first(itr)
2,966,377✔
469
    x = iterate(itr)
5,929,528✔
470
    x === nothing && throw(ArgumentError("collection must be non-empty"))
2,966,378✔
471
    x[1]
2,966,376✔
472
end
473

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

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

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

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

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

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

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

506
"""
507
    last(coll)
508

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

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

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

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

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

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

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

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

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

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

556
"""
557
    strides(A)
558

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

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

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

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

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

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

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

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

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

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

603
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
434,758✔
604
size_to_strides(s, d) = (s,)
119✔
605
size_to_strides(s) = ()
×
606

607

608
function isassigned(a::AbstractArray, i::Integer...)
189,345✔
609
    try
189,345✔
610
        a[i...]
309,584✔
611
        true
189,340✔
612
    catch e
613
        if isa(e, BoundsError) || isa(e, UndefRefError)
63✔
614
            return false
33✔
615
        else
616
            rethrow()
1✔
617
        end
618
    end
619
end
620

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

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

647
## Bounds checking ##
648

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

663
"""
664
    checkbounds(Bool, A, I...)
665

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

671
See also [`checkindex`](@ref).
672

673
# Examples
674
```jldoctest
675
julia> A = rand(3, 3);
676

677
julia> checkbounds(Bool, A, 2)
678
true
679

680
julia> checkbounds(Bool, A, 3, 4)
681
false
682

683
julia> checkbounds(Bool, A, 1:3)
684
true
685

686
julia> checkbounds(Bool, A, 1:3, 2:4)
687
false
688
```
689
"""
690
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
97,593,840✔
691
    @inline
97,593,840✔
692
    checkbounds_indices(Bool, axes(A), I)
98,639,662✔
693
end
694

695
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index
696
function checkbounds(::Type{Bool}, A::AbstractArray, i)
117,604,881✔
697
    @inline
115,954,586✔
698
    checkindex(Bool, eachindex(IndexLinear(), A), i)
2,454,454,157✔
699
end
700
# As a special extension, allow using logical arrays that match the source array exactly
701
function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{Bool,N}) where N
84✔
702
    @inline
84✔
703
    axes(A) == axes(I)
135✔
704
end
705

706
"""
707
    checkbounds(A, I...)
708

709
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
710
"""
711
function checkbounds(A::AbstractArray, I...)
610,621,908✔
712
    @inline
210,818,199✔
713
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
610,622,484✔
714
    nothing
610,621,438✔
715
end
716

717
"""
718
    checkbounds_indices(Bool, IA, I)
719

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

725
    checkbounds_indices(Bool, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
726
                                                          checkbounds_indices(Bool, IA, I)
727

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

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

735
See also [`checkbounds`](@ref).
736
"""
737
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
179,898,891✔
738
    @inline
13,781,341✔
739
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
315,332,490✔
740
end
741
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
5,367✔
742
    @inline
3,505✔
743
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
17,645✔
744
end
745
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
577,862✔
746
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
×
747

748
throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I)))
560✔
749

750
# check along a single dimension
751
"""
752
    checkindex(Bool, inds::AbstractUnitRange, index)
753

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

759
See also [`checkbounds`](@ref).
760

761
# Examples
762
```jldoctest
763
julia> checkindex(Bool, 1:20, 8)
764
true
765

766
julia> checkindex(Bool, 1:20, 21)
767
false
768
```
769
"""
770
checkindex(::Type{Bool}, inds::AbstractUnitRange, i) =
×
771
    throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
772
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
6,258,083✔
773
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
3,072,338✔
774
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
3,082,536,423✔
775
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
460✔
776
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
173✔
777
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
8,263,218✔
778
    @_propagate_inbounds_meta
921,872✔
779
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
312,876,895✔
780
end
781
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == axes1(I)
2✔
782
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool}) = false
1✔
783
function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
8,615✔
784
    @inline
5,019✔
785
    b = true
5,019✔
786
    for i in I
14,507✔
787
        b &= checkindex(Bool, inds, i)
6,343,757✔
788
    end
6,382,659✔
789
    b
12,032✔
790
end
791

792
# See also specializations in multidimensional
793

794
## Constructors ##
795

796
# default arguments to similar()
797
"""
798
    similar(array, [element_type=eltype(array)], [dims=size(array)])
799

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

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

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

812
```julia-repl
813
julia> similar(1:10, 1, 4)
814
1×4 Matrix{Int64}:
815
 4419743872  4374413872  4419743888  0
816
```
817

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

821
```julia-repl
822
julia> similar(trues(10,10), 2)
823
2-element BitVector:
824
 0
825
 0
826
```
827

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

831
```julia-repl
832
julia> similar(falses(10), Float64, 2, 4)
833
2×4 Matrix{Float64}:
834
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
835
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
836
```
837

838
See also: [`undef`](@ref), [`isassigned`](@ref).
839
"""
840
similar(a::AbstractArray{T}) where {T}                             = similar(a, T)
3,430✔
841
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
3,560✔
842
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
55,908,931✔
843
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
792✔
844
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
5,357,741✔
845
# Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
846
# thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
847
# but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
848
# define this method to convert supported axes to Ints, with the expectation that an offset array
849
# package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
850
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
57,585✔
851
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims))
5✔
852
# similar creates an Array by default
853
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N}    = Array{T,N}(undef, dims)
5,334,286✔
854

855
to_shape(::Tuple{}) = ()
398✔
856
to_shape(dims::Dims) = dims
5,519✔
857
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
6,620,162✔
858
# each dimension
859
to_shape(i::Int) = i
4✔
860
to_shape(i::Integer) = Int(i)
83✔
861
to_shape(r::OneTo) = Int(last(r))
63,387✔
862
to_shape(r::AbstractUnitRange) = r
192✔
863

864
"""
865
    similar(storagetype, axes)
866

867
Create an uninitialized mutable array analogous to that specified by
868
`storagetype`, but with `axes` specified by the last
869
argument.
870

871
**Examples**:
872

873
    similar(Array{Int}, axes(A))
874

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

881
    similar(BitArray, (axes(A, 2),))
882

883
would create a 1-dimensional logical array whose indices match those
884
of the columns of `A`.
885
"""
886
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
49✔
887
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
407,796,495✔
888
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
407,796,588✔
889

890
"""
891
    empty(v::AbstractVector, [eltype])
892

893
Create an empty vector similar to `v`, optionally changing the `eltype`.
894

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

897
# Examples
898

899
```jldoctest
900
julia> empty([1.0, 2.0, 3.0])
901
Float64[]
902

903
julia> empty([1.0, 2.0, 3.0], String)
904
String[]
905
```
906
"""
907
empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
288✔
908

909
# like empty, but should return a mutable collection, a Vector by default
910
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
201✔
911
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
52✔
912

913
"""
914
    copy!(dst, src) -> dst
915

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

922
See also [`copyto!`](@ref).
923

924
!!! compat "Julia 1.1"
925
    This method requires at least Julia 1.1. In Julia 1.0 this method
926
    is available from the `Future` standard library as `Future.copy!`.
927
"""
928
function copy!(dst::AbstractVector, src::AbstractVector)
50✔
929
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
50✔
930
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
931
    if length(dst) != length(src)
35,140,811✔
932
        resize!(dst, length(src))
35,140,731✔
933
    end
934
    copyto!(dst, src)
35,140,811✔
935
end
936

937
function copy!(dst::AbstractArray, src::AbstractArray)
15✔
938
    axes(dst) == axes(src) || throw(ArgumentError(
16✔
939
        "arrays must have the same axes for copy! (consider using `copyto!`)"))
940
    copyto!(dst, src)
14✔
941
end
942

943
## from general iterable to any array
944

945
# This is `Experimental.@max_methods 1 function copyto! end`, which is not
946
# defined at this point in bootstrap.
947
typeof(function copyto! end).name.max_methods = UInt8(1)
948

949
function copyto!(dest::AbstractArray, src)
3,524,447✔
950
    destiter = eachindex(dest)
3,524,486✔
951
    y = iterate(destiter)
4,620,127✔
952
    for x in src
5,722,443✔
953
        y === nothing &&
3,543,492✔
954
            throw(ArgumentError("destination has fewer elements than required"))
955
        dest[y[1]] = x
3,543,609✔
956
        y = iterate(destiter, y[2])
5,991,087✔
957
    end
5,505,921✔
958
    return dest
3,524,484✔
959
end
960

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

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

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

1039
## copy between abstract arrays - generally more efficient
1040
## since a single index variable can be used.
1041

1042
"""
1043
    copyto!(dest::AbstractArray, src) -> dest
1044

1045
Copy all elements from collection `src` to array `dest`, whose length must be greater than
1046
or equal to the length `n` of `src`. The first `n` elements of `dest` are overwritten,
1047
the other elements are left untouched.
1048

1049
See also [`copy!`](@ref Base.copy!), [`copy`](@ref).
1050

1051
# Examples
1052
```jldoctest
1053
julia> x = [1., 0., 3., 0., 5.];
1054

1055
julia> y = zeros(7);
1056

1057
julia> copyto!(y, x);
1058

1059
julia> y
1060
7-element Vector{Float64}:
1061
 1.0
1062
 0.0
1063
 3.0
1064
 0.0
1065
 5.0
1066
 0.0
1067
 0.0
1068
```
1069
"""
1070
function copyto!(dest::AbstractArray, src::AbstractArray)
2,762,214✔
1071
    isempty(src) && return dest
2,775,710✔
1072
    if dest isa BitArray
149,299✔
1073
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1074
        return _copyto_bitarray!(dest, src)
×
1075
    end
1076
    src′ = unalias(dest, src)
2,810,857✔
1077
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,775,256✔
1078
end
1079

1080
function copyto!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
×
1081
    isempty(src) && return dest
×
1082
    src′ = unalias(dest, src)
×
1083
    copyto_unaliased!(deststyle, dest, srcstyle, src′)
×
1084
end
1085

1086
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
2,775,256✔
1087
    isempty(src) && return dest
2,775,256✔
1088
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,775,259✔
1089
    idf, isf = first(destinds), first(srcinds)
149,299✔
1090
    Δi = idf - isf
149,299✔
1091
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,775,257✔
1092
        throw(BoundsError(dest, srcinds))
1093
    if deststyle isa IndexLinear
149,298✔
1094
        if srcstyle isa IndexLinear
144,808✔
1095
            # Single-index implementation
1096
            @inbounds for i in srcinds
5,272,021✔
1097
                dest[i + Δi] = src[i]
36,253,100✔
1098
            end
69,862,220✔
1099
        else
1100
            # Dual-index implementation
1101
            i = idf - 1
134,254✔
1102
            @inbounds for a in src
269,450✔
1103
                dest[i+=1] = a
4,811,447✔
1104
            end
9,480,771✔
1105
        end
1106
    else
1107
        iterdest, itersrc = eachindex(dest), eachindex(src)
4,490✔
1108
        if iterdest == itersrc
4,490✔
1109
            # Shared-iterator implementation
1110
            for I in iterdest
4,266✔
1111
                @inbounds dest[I] = src[I]
6,386,215✔
1112
            end
12,202,639✔
1113
        else
1114
            # Dual-iterator implementation
1115
            ret = iterate(iterdest)
4,714✔
1116
            @inbounds for a in src
4,402✔
1117
                idx, state = ret::NTuple{2,Any}
2,009,469✔
1118
                dest[idx] = a
2,009,469✔
1119
                ret = iterate(iterdest, state)
2,011,827✔
1120
            end
4,008,113✔
1121
        end
1122
    end
1123
    return dest
2,775,255✔
1124
end
1125

1126
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
20,842✔
1127
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
20,850✔
1128
end
1129

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

1136
function copyto!(dest::AbstractArray, dstart::Integer,
386,359✔
1137
               src::AbstractArray, sstart::Integer,
1138
               n::Integer)
1139
    n == 0 && return dest
386,359✔
1140
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
386,357✔
1141
        n," elements, but n should be nonnegative")))
1142
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
386,356✔
1143
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
386,368✔
1144
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
386,347✔
1145
    src′ = unalias(dest, src)
388,474✔
1146
    @inbounds for i = 0:n-1
772,682✔
1147
        dest[dstart+i] = src′[sstart+i]
19,316,964✔
1148
    end
38,247,587✔
1149
    return dest
386,341✔
1150
end
1151

1152
function copy(a::AbstractArray)
550✔
1153
    @_propagate_inbounds_meta
503✔
1154
    copymutable(a)
1,231✔
1155
end
1156

1157
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
3,783✔
1158
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1159
    if length(ir_dest) != length(ir_src)
3,783✔
1160
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1161
            length(ir_src)," and ",length(ir_dest),")")))
1162
    end
1163
    if length(jr_dest) != length(jr_src)
3,782✔
1164
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1165
            length(jr_src)," and ",length(jr_dest),")")))
1166
    end
1167
    @boundscheck checkbounds(B, ir_dest, jr_dest)
3,782✔
1168
    @boundscheck checkbounds(A, ir_src, jr_src)
3,782✔
1169
    A′ = unalias(B, A)
7,562✔
1170
    jdest = first(jr_dest)
3,782✔
1171
    for jsrc in jr_src
7,564✔
1172
        idest = first(ir_dest)
23,833✔
1173
        for isrc in ir_src
47,666✔
1174
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
211,382✔
1175
            idest += step(ir_dest)
211,222✔
1176
        end
398,611✔
1177
        jdest += step(jr_dest)
23,833✔
1178
    end
43,884✔
1179
    return B
3,782✔
1180
end
1181

1182
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
49,954✔
1183

1184
function copyto_axcheck!(dest, src)
44,722✔
1185
    _checkaxs(axes(dest), axes(src))
49,929✔
1186
    copyto!(dest, src)
60,406✔
1187
end
1188

1189
"""
1190
    copymutable(a)
1191

1192
Make a mutable copy of an array or iterable `a`.  For `a::Array`,
1193
this is equivalent to `copy(a)`, but for other array types it may
1194
differ depending on the type of `similar(a)`.  For generic iterables
1195
this is equivalent to `collect(a)`.
1196

1197
# Examples
1198
```jldoctest
1199
julia> tup = (1, 2, 3)
1200
(1, 2, 3)
1201

1202
julia> Base.copymutable(tup)
1203
3-element Vector{Int64}:
1204
 1
1205
 2
1206
 3
1207
```
1208
"""
1209
function copymutable(a::AbstractArray)
3,934✔
1210
    @_propagate_inbounds_meta
1,335✔
1211
    copyto!(similar(a), a)
8,148✔
1212
end
1213
copymutable(itr) = collect(itr)
1✔
1214

1215
zero(x::AbstractArray{T}) where {T} = fill!(similar(x, typeof(zero(T))), zero(T))
11,844✔
1216

1217
## iteration support for arrays by iterating over `eachindex` in the array ##
1218
# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1219

1220
# While the definitions for IndexLinear are all simple enough to inline on their
1221
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1222
# inlining.
1223
function iterate(A::AbstractArray, state=(eachindex(A),))
112,603,822✔
1224
    y = iterate(state...)
138,126,808✔
1225
    y === nothing && return nothing
114,454,225✔
1226
    A[y[1]], (state[1], tail(y)...)
113,965,025✔
1227
end
1228

1229
isempty(a::AbstractArray) = (length(a) == 0)
2,556,284,222✔
1230

1231

1232
## range conversions ##
1233

1234
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
2✔
1235
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
162✔
1236
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
6✔
1237
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
1✔
1238
    LinRange(T(r.start), T(r.stop), length(r))
1✔
1239
end
1240

1241
## unsafe/pointer conversions ##
1242

1243
# note: the following type definitions don't mean any AbstractArray is convertible to
1244
# a data Ref. they just map the array element type to the pointer type for
1245
# convenience in cases that work.
1246
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
30,459,741✔
1247
function pointer(x::AbstractArray{T}, i::Integer) where T
8,476,198✔
1248
    @inline
5,314,795✔
1249
    unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
301,516,204✔
1250
end
1251

1252
# The distance from pointer(x) to the element at x[I...] in bytes
1253
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
259,161,559✔
1254
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
100,920✔
1255
    J = _to_subscript_indices(x, I...)
100,920✔
1256
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
378,433✔
1257
end
1258

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

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

1275
# Examples
1276
```jldoctest
1277
julia> A = [1 2; 3 4]
1278
2×2 Matrix{Int64}:
1279
 1  2
1280
 3  4
1281

1282
julia> getindex(A, 1)
1283
1
1284

1285
julia> getindex(A, [2, 1])
1286
2-element Vector{Int64}:
1287
 3
1288
 1
1289

1290
julia> getindex(A, 2:4)
1291
3-element Vector{Int64}:
1292
 3
1293
 2
1294
 4
1295
```
1296
"""
1297
function getindex(A::AbstractArray, I...)
115,026,525✔
1298
    @_propagate_inbounds_meta
112,416,779✔
1299
    error_if_canonical_getindex(IndexStyle(A), A, I...)
112,416,779✔
1300
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
238,306,802✔
1301
end
1302
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1303
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
157,133,204✔
1304

1305
function unsafe_getindex(A::AbstractArray, I...)
264✔
1306
    @inline
264✔
1307
    @inbounds r = getindex(A, I...)
389✔
1308
    r
262✔
1309
end
1310

1311
struct CanonicalIndexError <: Exception
1312
    func::String
1313
    type::Any
1314
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
14✔
1315
end
1316

1317
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1318
    throw(CanonicalIndexError("getindex", typeof(A)))
1319
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1320
    throw(CanonicalIndexError("getindex", typeof(A)))
1321
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
112,415,401✔
1322

1323
## Internal definitions
1324
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1325
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1326

1327
## IndexLinear Scalar indexing: canonical method is one Int
1328
_getindex(::IndexLinear, A::AbstractVector, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))  # ambiguity resolution in case packages specialize this (to be avoided if at all possible, but see Interpolations.jl)
18,183,677✔
1329
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
51✔
1330
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
1,926,019✔
1331
    @inline
928,505✔
1332
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
37,408,773✔
1333
    @inbounds r = getindex(A, _to_linear_index(A, I...))
37,408,721✔
1334
    r
37,408,693✔
1335
end
1336
_to_linear_index(A::AbstractArray, i::Integer) = i
227,193✔
1337
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1,789,118✔
1338
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
323,593✔
1339
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
1,794,843✔
1340

1341
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1342
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
317,669✔
1343
    @inline
317,669✔
1344
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
317,742✔
1345
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
328,816✔
1346
    r
317,595✔
1347
end
1348
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
94,598,894✔
1349
    @_propagate_inbounds_meta
94,598,894✔
1350
    getindex(A, I...)
182,046,202✔
1351
end
1352
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
390,296✔
1353
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1354
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1355
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
417✔
1356
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1357
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1,605✔
1358
    @inline
1,605✔
1359
    J, Jrem = IteratorsMD.split(I, Val(N))
1,605✔
1360
    _to_subscript_indices(A, J, Jrem)
1,605✔
1361
end
1362
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1363
    __to_subscript_indices(A, axes(A), J, Jrem)
1364
function __to_subscript_indices(A::AbstractArray,
2✔
1365
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1366
    @inline
2✔
1367
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1368
end
1369
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
1,603✔
1370
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
29,828✔
1371
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1372
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1373
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1374
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
390,296✔
1375

1376
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1377
# function that allows dispatch on array storage
1378

1379
"""
1380
    setindex!(A, X, inds...)
1381
    A[inds...] = X
1382

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

1386
# Examples
1387
```jldoctest
1388
julia> A = zeros(2,2);
1389

1390
julia> setindex!(A, [10, 20], [1, 2]);
1391

1392
julia> A[[3, 4]] = [30, 40];
1393

1394
julia> A
1395
2×2 Matrix{Float64}:
1396
 10.0  30.0
1397
 20.0  40.0
1398
```
1399
"""
1400
function setindex!(A::AbstractArray, v, I...)
2,526,034✔
1401
    @_propagate_inbounds_meta
2,526,023✔
1402
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,526,023✔
1403
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
2,543,959✔
1404
end
1405
function unsafe_setindex!(A::AbstractArray, v, I...)
732✔
1406
    @inline
732✔
1407
    @inbounds r = setindex!(A, v, I...)
732✔
1408
    r
730✔
1409
end
1410

1411
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
7✔
1412
    throw(CanonicalIndexError("setindex!", typeof(A)))
1413
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1414
    throw(CanonicalIndexError("setindex!", typeof(A)))
1415
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
2,526,014✔
1416

1417
## Internal definitions
1418
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1419
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1420

1421
## IndexLinear Scalar indexing
1422
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
13,805✔
1423
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
122,937✔
1424
    @inline
106,155✔
1425
    @boundscheck checkbounds(A, I...)
127,015✔
1426
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
126,990✔
1427
    r
126,989✔
1428
end
1429

1430
# IndexCartesian Scalar indexing
1431
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,392,288✔
1432
    @_propagate_inbounds_meta
2,392,288✔
1433
    setindex!(A, v, I...)
2,392,387✔
1434
end
1435
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
887✔
1436
    @inline
887✔
1437
    @boundscheck checkbounds(A, I...)
892✔
1438
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
882✔
1439
    r
882✔
1440
end
1441

1442
"""
1443
    parent(A)
1444

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

1450
# Examples
1451
```jldoctest
1452
julia> A = [1 2; 3 4]
1453
2×2 Matrix{Int64}:
1454
 1  2
1455
 3  4
1456

1457
julia> V = view(A, 1:2, :)
1458
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1459
 1  2
1460
 3  4
1461

1462
julia> parent(V)
1463
2×2 Matrix{Int64}:
1464
 1  2
1465
 3  4
1466
```
1467
"""
1468
parent(a::AbstractArray) = a
1,541✔
1469

1470
## rudimentary aliasing detection ##
1471
"""
1472
    Base.unalias(dest, A)
1473

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

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

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

1484
See also [`Base.mightalias`](@ref).
1485
"""
1486
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
8,656,825✔
1487
unalias(dest, A::AbstractRange) = A
2,549,980✔
1488
unalias(dest, A) = A
2,544,416✔
1489

1490
"""
1491
    Base.unaliascopy(A)
1492

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

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

1513
"""
1514
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1515

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

1518
By default, this simply checks if either of the arrays reference the same memory
1519
regions, as identified by their [`Base.dataids`](@ref).
1520
"""
1521
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !_isdisjoint(dataids(A), dataids(B))
5,881,257✔
1522
mightalias(x, y) = false
×
1523

1524
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1525
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1526
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1527
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1528
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
5,766,277✔
1529
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
85,667✔
1530
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1531
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
5,858✔
1532
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
83,868✔
1533

1534
"""
1535
    Base.dataids(A::AbstractArray)
1536

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

1539
Custom arrays that would like to opt-in to aliasing detection of their component
1540
parts can specialize this method to return the concatenation of the `dataids` of
1541
their component parts.  A typical definition for an array that wraps a parent is
1542
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1543
"""
1544
dataids(A::AbstractArray) = (UInt(objectid(A)),)
199,953✔
1545
dataids(A::Array) = (UInt(pointer(A)),)
11,459,541✔
1546
dataids(::AbstractRange) = ()
20,428✔
1547
dataids(x) = ()
6,837✔
1548

1549
## get (getindex with a default value) ##
1550

1551
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1552
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1553

1554
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
11✔
1555
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
8✔
1556
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
16✔
1557
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
4✔
1558
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
8✔
1559
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
9✔
1560

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

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

1581
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
2✔
1582
    fill!(X, default)
72✔
1583
    dst, src = indcopy(size(A), I)
2✔
1584
    X[dst...] = A[src...]
2✔
1585
    X
2✔
1586
end
1587

1588
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1589
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1590

1591
## structured matrix methods ##
1592
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
24,420✔
1593
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
5,167✔
1594

1595
## Concatenation ##
1596
eltypeof(x) = typeof(x)
1,422✔
1597
eltypeof(x::AbstractArray) = eltype(x)
859✔
1598

1599
promote_eltypeof() = Bottom
×
1600
promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
2,281✔
1601

1602
promote_eltype() = Bottom
3,184✔
1603
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
14,027✔
1604

1605
#TODO: ERROR CHECK
1606
_cat(catdim::Int) = Vector{Any}()
1✔
1607

1608
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1609
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1610

1611
## cat: special cases
1612
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
52✔
1613
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
288✔
1614
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
97✔
1615
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
518✔
1616

1617
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
1✔
1618
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
2✔
1619
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
8✔
1620
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
59✔
1621

1622
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
5✔
1623
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
13✔
1624

1625
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1626
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1627
# but that solution currently fails (see #27188 and #27224)
1628
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1629

1630
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
793,076✔
1631
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
819,333✔
1632
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1633

1634
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
793,076✔
1635
    pos = 1
793,076✔
1636
    for k=1:Int(length(V))::Int
793,081✔
1637
        Vk = V[k]
794,333✔
1638
        p1 = pos + Int(length(Vk))::Int - 1
794,830✔
1639
        a[pos:p1] = Vk
5,720,068✔
1640
        pos = p1+1
794,333✔
1641
    end
795,590✔
1642
    a
793,076✔
1643
end
1644

1645
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
444✔
1646

1647
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
17✔
1648
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
23✔
1649

1650
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
450✔
1651
    nargs = length(A)
450✔
1652
    nrows = size(A[1], 1)
451✔
1653
    ncols = 0
450✔
1654
    dense = true
450✔
1655
    for j = 1:nargs
456✔
1656
        Aj = A[j]
926✔
1657
        if size(Aj, 1) != nrows
1,190✔
1658
            throw(ArgumentError("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1659
        end
1660
        dense &= isa(Aj,Array)
925✔
1661
        nd = ndims(Aj)
1,189✔
1662
        ncols += (nd==2 ? size(Aj,2) : 1)
1,135✔
1663
    end
1,401✔
1664
    B = similar(A[1], T, nrows, ncols)
449✔
1665
    pos = 1
449✔
1666
    if dense
449✔
1667
        for k=1:nargs
184✔
1668
            Ak = A[k]
382✔
1669
            n = length(Ak)
401✔
1670
            copyto!(B, pos, Ak, 1, n)
401✔
1671
            pos += n
382✔
1672
        end
582✔
1673
    else
1674
        for k=1:nargs
271✔
1675
            Ak = A[k]
542✔
1676
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
737✔
1677
            B[:, pos:p1] = Ak
542✔
1678
            pos = p1+1
542✔
1679
        end
542✔
1680
    end
1681
    return B
449✔
1682
end
1683

1684
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
12✔
1685
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
16✔
1686

1687
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
791✔
1688
    nargs = length(A)
791✔
1689
    nrows = sum(a->size(a, 1), A)::Int
2,480✔
1690
    ncols = size(A[1], 2)
791✔
1691
    for j = 2:nargs
792✔
1692
        if size(A[j], 2) != ncols
848✔
1693
            throw(ArgumentError("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1694
        end
1695
    end
920✔
1696
    B = similar(A[1], T, nrows, ncols)
790✔
1697
    pos = 1
790✔
1698
    for k=1:nargs
791✔
1699
        Ak = A[k]
1,637✔
1700
        p1 = pos+size(Ak,1)::Int-1
1,713✔
1701
        B[pos:p1, :] = Ak
1,637✔
1702
        pos = p1+1
1,637✔
1703
    end
2,484✔
1704
    return B
790✔
1705
end
1706

1707
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
814,946✔
1708

1709
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1710
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1711

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

1715
## cat: general case
1716

1717
# helper functions
1718
cat_size(A) = (1,)
2,066✔
1719
cat_size(A::AbstractArray) = size(A)
4,505✔
1720
cat_size(A, d) = 1
2,479✔
1721
cat_size(A::AbstractArray, d) = size(A, d)
12,157✔
1722

1723
cat_length(::Any) = 1
100✔
1724
cat_length(a::AbstractArray) = length(a)
465✔
1725

1726
cat_ndims(a) = 0
183✔
1727
cat_ndims(a::AbstractArray) = ndims(a)
674✔
1728

1729
cat_indices(A, d) = OneTo(1)
2,067✔
1730
cat_indices(A::AbstractArray, d) = axes(A, d)
5,664✔
1731

1732
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
588✔
1733
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1734
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,142✔
1735
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1736
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
950✔
1737
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
×
1738

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

1754
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1755
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1756
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
589✔
1757
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
559✔
1758
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1759
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
3,665✔
1760
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1761
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
16✔
1762
    _cs(ndim, shape[1], 1)
18✔
1763
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
14✔
1764
end
1765
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
250✔
1766
    next = _cs(ndim, shape[1], nshape[1])
250✔
1767
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
250✔
1768
end
1769
@inline function _cshp(ndim::Int, dims, shape, nshape)
5,061✔
1770
    a = shape[1]
5,061✔
1771
    b = nshape[1]
5,061✔
1772
    next = dims[1] ? a + b : _cs(ndim, a, b)
5,949✔
1773
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
5,088✔
1774
end
1775

1776
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,656✔
1777
    "mismatch in dimension $d (expected $a got $b)")))
1778

1779
dims2cat(::Val{dims}) where dims = dims2cat(dims)
1,037✔
1780
function dims2cat(dims)
1,644✔
1781
    if any(≤(0), dims)
2,827✔
1782
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1783
    end
1784
    ntuple(in(dims), maximum(dims))
1,672✔
1785
end
1786

1787
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
517✔
1788

1789
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
2,636✔
1790
    catdims = dims2cat(dims)
2,666✔
1791
    shape = cat_size_shape(catdims, X...)
2,638✔
1792
    A = cat_similar(X[1], T, shape)
2,633✔
1793
    if count(!iszero, catdims)::Int > 1
2,630✔
1794
        fill!(A, zero(T))
591✔
1795
    end
1796
    return __cat(A, shape, catdims, X...)
3,158✔
1797
end
1798
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1799
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1800
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1801

1802
# Why isn't this called `__cat!`?
1803
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
3,158✔
1804

1805
function __cat_offset!(A, shape, catdims, offsets, x, X...)
6,560✔
1806
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1807
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
7,089✔
1808
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
6,562✔
1809
end
1810
__cat_offset!(A, shape, catdims, offsets) = A
2,628✔
1811

1812
function __cat_offset1!(A, shape, catdims, offsets, x)
6,560✔
1813
    inds = ntuple(length(offsets)) do i
6,714✔
1814
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
10,975✔
1815
    end
1816
    if x isa AbstractArray
6,557✔
1817
        A[inds...] = x
71,850✔
1818
    else
1819
        fill!(view(A, inds...), x)
2,950✔
1820
    end
1821
    newoffsets = ntuple(length(offsets)) do i
6,562✔
1822
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
13,177✔
1823
    end
1824
    return newoffsets
6,562✔
1825
end
1826

1827
"""
1828
    vcat(A...)
1829

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

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

1836
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1837

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

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

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

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

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

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

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

1871
julia> vs = [[1, 2], [3, 4], [5, 6]];
1872

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

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

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

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

1897
See also [`vcat`](@ref), [`hvcat`](@ref).
1898

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

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

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

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

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

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

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

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

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

1938
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
167✔
1939
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
323✔
1940

1941
"""
1942
    cat(A...; dims)
1943

1944
Concatenate the input arrays along the dimensions specified in `dims`.
1945

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

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

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

1960
The keyword also accepts `Val(dims)`.
1961

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

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

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

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

1989
# The specializations for 1 and 2 inputs are important
1990
# especially when running with --inline=no, see #11158
1991
# The specializations for Union{AbstractVecOrMat,Number} are necessary
1992
# to have more specialized methods here than in LinearAlgebra/uniformscaling.jl
1993
vcat(A::AbstractArray) = cat(A; dims=Val(1))
1✔
1994
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
5✔
1995
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
1996
vcat(A::Union{AbstractVecOrMat,Number}...) = cat(A...; dims=Val(1))
107✔
1997
hcat(A::AbstractArray) = cat(A; dims=Val(2))
1✔
1998
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
1✔
1999
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
1✔
2000
hcat(A::Union{AbstractVecOrMat,Number}...) = cat(A...; dims=Val(2))
×
2001

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

2009
# 2d horizontal and vertical concatenation
2010

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

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

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

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

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

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

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

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

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

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

2068
    nc = 0
373✔
2069
    for i=1:rows[1]
746✔
2070
        nc += size(as[i],2)
714✔
2071
    end
1,055✔
2072

2073
    nr = 0
373✔
2074
    a = 1
373✔
2075
    for i = 1:nbr
373✔
2076
        nr += size(as[a],1)
569✔
2077
        a += rows[i]
569✔
2078
    end
765✔
2079

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

2082
    a = 1
373✔
2083
    r = 1
373✔
2084
    for i = 1:nbr
373✔
2085
        c = 1
569✔
2086
        szi = size(as[a],1)
569✔
2087
        for j = 1:rows[i]
1,138✔
2088
            Aj = as[a+j-1]
985✔
2089
            szj = size(Aj,2)
985✔
2090
            if size(Aj,1) != szi
985✔
2091
                throw(ArgumentError("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
1✔
2092
            end
2093
            if c-1+szj > nc
1,879✔
2094
                throw(ArgumentError("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
1✔
2095
            end
2096
            out[r:r-1+szi, c:c-1+szj] = Aj
983✔
2097
            c += szj
983✔
2098
        end
1,399✔
2099
        if c != nc+1
567✔
2100
            throw(ArgumentError("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
1✔
2101
        end
2102
        r += szi
566✔
2103
        a += rows[i]
566✔
2104
    end
762✔
2105
    out
370✔
2106
end
2107

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

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

2115
    a = Matrix{T}(undef, nr, nc)
1,237✔
2116
    if length(a) != length(xs)
1,237✔
2117
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2118
    end
2119
    k = 1
488✔
2120
    @inbounds for i=1:nr
1,235✔
2121
        if nc != rows[i]
3,239✔
2122
            throw(ArgumentError("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2123
        end
2124
        for j=1:nc
6,476✔
2125
            a[i,j] = xs[k]
8,757✔
2126
            k += 1
8,757✔
2127
        end
14,276✔
2128
    end
5,242✔
2129
    a
1,234✔
2130
end
2131

2132
function hvcat_fill!(a::Array, xs::Tuple)
447✔
2133
    nr, nc = size(a,1), size(a,2)
447✔
2134
    len = length(xs)
447✔
2135
    if nr*nc != len
447✔
2136
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2137
    end
2138
    k = 1
446✔
2139
    for i=1:nr
892✔
2140
        @inbounds for j=1:nc
2,416✔
2141
            a[i,j] = xs[k]
9,111✔
2142
            k += 1
8,470✔
2143
        end
15,732✔
2144
    end
1,970✔
2145
    a
446✔
2146
end
2147

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

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

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

2175
## N-dimensional concatenation ##
2176

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2272

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

2276
# 1-dimensional hvncat methods
2277

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

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

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

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

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

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

2319
    nd = N
16✔
2320

2321
    Ndim = 0
16✔
2322
    for i ∈ eachindex(as)
17✔
2323
        Ndim += cat_size(as[i], N)
36✔
2324
        nd = max(nd, cat_ndims(as[i]))
36✔
2325
        for d ∈ 1:N - 1
30✔
2326
            cat_size(as[1], d) == cat_size(as[i], d) || throw(ArgumentError("mismatched size along axis $d in element $i"))
35✔
2327
        end
38✔
2328
    end
40✔
2329

2330
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
25✔
2331
    k = 1
12✔
2332
    for a ∈ as
12✔
2333
        for i ∈ eachindex(a)
40✔
2334
            A[k] = a[i]
26✔
2335
            k += 1
24✔
2336
        end
29✔
2337
    end
31✔
2338
    return A
12✔
2339
end
2340

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

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

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

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

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

2378

2379
# balanced dimensions hvncat methods
2380

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

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

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

2410
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
63✔
2411
    # putting these in separate functions leads to unnecessary allocations
2412
    if row_first
63✔
2413
        nr, nc = size(A, 1), size(A, 2)
17✔
2414
        nrc = nr * nc
17✔
2415
        na = prod(size(A)[3:end])
17✔
2416
        k = 1
17✔
2417
        for d ∈ 1:na
34✔
2418
            dd = nrc * (d - 1)
31✔
2419
            for i ∈ 1:nr
62✔
2420
                Ai = dd + i
42✔
2421
                for j ∈ 1:nc
84✔
2422
                    A[Ai] = xs[k]
95✔
2423
                    k += 1
95✔
2424
                    Ai += nr
95✔
2425
                end
148✔
2426
            end
53✔
2427
        end
31✔
2428
    else
2429
        for k ∈ eachindex(xs)
46✔
2430
            A[k] = xs[k]
93✔
2431
        end
93✔
2432
    end
2433
end
2434

2435
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
89✔
2436
    # function barrier after calculating the max is necessary for high performance
2437
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
89✔
2438
    return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
123✔
2439
end
2440

2441
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
89✔
2442
    length(as) > 0 ||
89✔
2443
        throw(ArgumentError("must have at least one element"))
2444
    all(>(0), dims) ||
121✔
2445
        throw(ArgumentError("`dims` argument must contain positive integers"))
2446

2447
    d1 = row_first ? 2 : 1
57✔
2448
    d2 = row_first ? 1 : 2
57✔
2449

2450
    outdims = zeros(Int, N)
200✔
2451

2452
    # validate shapes for lowest level of concatenation
2453
    d = findfirst(>(1), dims)
84✔
2454
    if d !== nothing # all dims are 1
57✔
2455
        if row_first && d < 3
56✔
2456
            d = d == 1 ? 2 : 1
31✔
2457
        end
2458
        nblocks = length(as) ÷ dims[d]
56✔
2459
        for b ∈ 1:nblocks
112✔
2460
            offset = ((b - 1) * dims[d])
171✔
2461
            startelementi = offset + 1
171✔
2462
            for i ∈ offset .+ (2:dims[d])
258✔
2463
                for dd ∈ 1:N
111✔
2464
                    dd == d && continue
316✔
2465
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
217✔
2466
                        throw(ArgumentError("incompatible shape in element $i"))
6✔
2467
                    end
2468
                end
515✔
2469
            end
129✔
2470
        end
280✔
2471
    end
2472

2473
    # discover number of rows or columns
2474
    for i ∈ 1:dims[d1]
102✔
2475
        outdims[d1] += cat_size(as[i], d1)
138✔
2476
    end
161✔
2477

2478
    currentdims = zeros(Int, N)
173✔
2479
    blockcount = 0
51✔
2480
    elementcount = 0
51✔
2481
    for i ∈ eachindex(as)
51✔
2482
        elementcount += cat_length(as[i])
305✔
2483
        currentdims[d1] += cat_size(as[i], d1)
305✔
2484
        if currentdims[d1] == outdims[d1]
255✔
2485
            currentdims[d1] = 0
127✔
2486
            for d ∈ (d2, 3:N...)
127✔
2487
                currentdims[d] += cat_size(as[i], d)
254✔
2488
                if outdims[d] == 0 # unfixed dimension
199✔
2489
                    blockcount += 1
164✔
2490
                    if blockcount == dims[d]
164✔
2491
                        outdims[d] = currentdims[d]
86✔
2492
                        currentdims[d] = 0
86✔
2493
                        blockcount = 0
86✔
2494
                    else
2495
                        break
164✔
2496
                    end
2497
                else # fixed dimension
2498
                    if currentdims[d] == outdims[d] # end of dimension
35✔
2499
                        currentdims[d] = 0
22✔
2500
                    elseif currentdims[d] < outdims[d] # dimension in progress
13✔
2501
                        break
13✔
2502
                    else # exceeded dimension
2503
                        throw(ArgumentError("argument $i has too many elements along axis $d"))
×
2504
                    end
2505
                end
2506
            end
138✔
2507
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
128✔
2508
            throw(ArgumentError("argument $i has too many elements along axis $d1"))
16✔
2509
        end
2510
    end
443✔
2511

2512
    outlen = prod(outdims)
70✔
2513
    elementcount == outlen ||
35✔
2514
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2515

2516
    # copy into final array
2517
    A = cat_similar(as[1], T, outdims)
35✔
2518
    # @assert all(==(0), currentdims)
2519
    outdims .= 0
105✔
2520
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
35✔
2521
    return A
35✔
2522
end
2523

2524

2525
# unbalanced dimensions hvncat methods
2526

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

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

2539
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
106✔
2540
    length(as) > 0 ||
106✔
2541
        throw(ArgumentError("must have at least one element"))
2542
    all(>(0), tuple((shape...)...)) ||
146✔
2543
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2544

2545
    d1 = row_first ? 2 : 1
66✔
2546
    d2 = row_first ? 1 : 2
66✔
2547

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

2563
    elementcount = 0
63✔
2564
    for i ∈ eachindex(as)
63✔
2565
        elementcount += cat_length(as[i])
351✔
2566
        wasstartblock = false
310✔
2567
        for d ∈ 1:N
310✔
2568
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
898✔
2569
            dsize = cat_size(as[i], ad)
1,036✔
2570
            blockcounts[d] += 1
898✔
2571

2572
            if d == 1 || i == 1 || wasstartblock
1,486✔
2573
                currentdims[d] += dsize
616✔
2574
            elseif dsize != cat_size(as[i - 1], ad)
300✔
2575
                throw(ArgumentError("argument $i has a mismatched number of elements along axis $ad; \
8✔
2576
                                    expected $(cat_size(as[i - 1], ad)), got $dsize"))
2577
            end
2578

2579
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
890✔
2580

2581
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
890✔
2582
            if isendblock
890✔
2583
                if outdims[d] == -1
264✔
2584
                    outdims[d] = currentdims[d]
135✔
2585
                elseif outdims[d] != currentdims[d]
129✔
2586
                    throw(ArgumentError("argument $i has a mismatched number of elements along axis $ad; \
40✔
2587
                                        expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2588
                end
2589
                currentdims[d] = 0
224✔
2590
                blockcounts[d] = 0
224✔
2591
                shapepos[d] += 1
224✔
2592
                d > 1 && (blockcounts[d - 1] == 0 ||
225✔
2593
                    throw(ArgumentError("shape in level $d is inconsistent; level counts must nest \
2594
                                        evenly into each other")))
2595
            end
2596
        end
1,437✔
2597
    end
508✔
2598

2599
    outlen = prod(outdims)
28✔
2600
    elementcount == outlen ||
14✔
2601
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2602

2603
    if row_first
14✔
2604
        outdims[1], outdims[2] = outdims[2], outdims[1]
10✔
2605
    end
2606

2607
    # @assert all(==(0), currentdims)
2608
    # @assert all(==(0), blockcounts)
2609

2610
    # copy into final array
2611
    A = cat_similar(as[1], T, outdims)
14✔
2612
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
14✔
2613
    return A
14✔
2614
end
2615

2616
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int}, d1::Int, d2::Int, as::Tuple{Vararg}) where {T, N}
49✔
2617
    outdims = size(A)
49✔
2618
    offsets = scratch1
49✔
2619
    inneroffsets = scratch2
49✔
2620
    for a ∈ as
49✔
2621
        if isa(a, AbstractArray)
263✔
2622
            for ai ∈ a
253✔
2623
                Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
6,966✔
2624
                A[Ai] = ai
1,848✔
2625

2626
                for j ∈ 1:N
1,848✔
2627
                    inneroffsets[j] += 1
4,097✔
2628
                    inneroffsets[j] < cat_size(a, j) && break
4,153✔
2629
                    inneroffsets[j] = 0
2,468✔
2630
                end
2,468✔
2631
            end
2,054✔
2632
        else
2633
            Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2634
            A[Ai] = a
30✔
2635
        end
2636

2637
        for j ∈ (d1, d2, 3:N...)
263✔
2638
            offsets[j] += cat_size(a, j)
581✔
2639
            offsets[j] < outdims[j] && break
503✔
2640
            offsets[j] = 0
294✔
2641
        end
294✔
2642
    end
263✔
2643
end
2644

2645
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
1,875✔
2646
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2647
    Ai = inneroffsets[1] + offsets[1] + 1
1,875✔
2648
    for j ∈ 2:nd
1,875✔
2649
        increment = inneroffsets[j] + offsets[j]
7,018✔
2650
        for k ∈ 1:j-1
14,008✔
2651
            increment *= outdims[k]
17,089✔
2652
        end
27,160✔
2653
        Ai += increment
7,018✔
2654
    end
12,161✔
2655
    Ai
1,875✔
2656
end
2657

2658
"""
2659
    stack(iter; [dims])
2660

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

2664
By default the axes of the elements are placed first,
2665
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2666
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2667

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

2672
The various [`cat`](@ref) functions also combine arrays. However, these all
2673
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2674
the arrays along new dimensions.
2675
They also accept arrays as separate arguments, rather than a single collection.
2676

2677
!!! compat "Julia 1.9"
2678
    This function requires at least Julia 1.9.
2679

2680
# Examples
2681
```jldoctest
2682
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2683

2684
julia> mat = stack(vecs)
2685
2×3 Matrix{Float32}:
2686
 1.0  30.0  500.0
2687
 2.0  40.0  600.0
2688

2689
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2690
true
2691

2692
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2693
true
2694

2695
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2696
2×4 Matrix{Int64}:
2697
  1   2   3   4
2698
 10  11  12  13
2699

2700
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2701
true
2702

2703
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2704
3×2 Matrix{Float32}:
2705
   1.0    2.0
2706
  30.0   40.0
2707
 500.0  600.0
2708

2709
julia> x = rand(3,4);
2710

2711
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2712
true
2713
```
2714

2715
Higher-dimensional examples:
2716

2717
```jldoctest
2718
julia> A = rand(5, 7, 11);
2719

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

2722
julia> (element = size(first(E)), container = size(E))
2723
(element = (5, 11), container = (7,))
2724

2725
julia> stack(E) |> size
2726
(5, 11, 7)
2727

2728
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2729
true
2730

2731
julia> A == stack(E; dims=2)
2732
true
2733

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

2736
julia> (element = size(first(M)), container = size(M))
2737
(element = (2, 3), container = (5, 7))
2738

2739
julia> stack(M) |> size  # keeps all dimensions
2740
(2, 3, 5, 7)
2741

2742
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2743
(35, 2, 3)
2744

2745
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2746
(14, 15)
2747
```
2748
"""
2749
stack(iter; dims=:) = _stack(dims, iter)
250✔
2750

2751
"""
2752
    stack(f, args...; [dims])
2753

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

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

2761
See also [`mapslices`](@ref), [`eachcol`](@ref).
2762

2763
# Examples
2764
```jldoctest
2765
julia> stack(c -> (c, c-32), "julia")
2766
2×5 Matrix{Char}:
2767
 'j'  'u'  'l'  'i'  'a'
2768
 'J'  'U'  'L'  'I'  'A'
2769

2770
julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2771
         vcat(row, row .* n, row ./ n)
2772
       end
2773
2×9 Matrix{Float64}:
2774
 1.0  2.0  3.0   10.0   20.0   30.0  0.1   0.2   0.3
2775
 4.0  5.0  6.0  400.0  500.0  600.0  0.04  0.05  0.06
2776
```
2777
"""
2778
stack(f, iter; dims=:) = _stack(dims, f(x) for x in iter)
12✔
2779
stack(f, xs, yzs...; dims=:) = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
2✔
2780

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

2783
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2784

2785
function _stack(dims, ::Union{HasShape, HasLength}, iter)
122✔
2786
    S = @default_eltype iter
122✔
2787
    T = S != Union{} ? eltype(S) : Any  # Union{} occurs for e.g. stack(1,2), postpone the error
126✔
2788
    if isconcretetype(T)
122✔
2789
        _typed_stack(dims, T, S, iter)
103✔
2790
    else  # Need to look inside, but shouldn't run an expensive iterator twice:
2791
        array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
42✔
2792
        isempty(array) && return _empty_stack(dims, T, S, iter)
38✔
2793
        T2 = mapreduce(eltype, promote_type, array)
42✔
2794
        _typed_stack(dims, T2, eltype(array), array)
36✔
2795
    end
2796
end
2797

2798
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
184✔
2799
    xit = iterate(A)
210✔
2800
    nothing === xit && return _empty_stack(:, T, S, A)
94✔
2801
    x1, _ = xit
94✔
2802
    ax1 = _iterator_axes(x1)
98✔
2803
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
106✔
2804
    off = firstindex(B)
93✔
2805
    len = length(x1)
97✔
2806
    while xit !== nothing
2,563✔
2807
        x, state = xit
2,476✔
2808
        _stack_size_check(x, ax1)
4,654✔
2809
        copyto!(B, off, x)
2,474✔
2810
        off += len
2,470✔
2811
        xit = iterate(A, state)
3,798✔
2812
    end
2,470✔
2813
    B
87✔
2814
end
2815

2816
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2817
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2818
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2819

2820
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2821
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
51✔
2822
    _typed_stack(dims, T, S, IteratorSize(S), A)
2823
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
13✔
2824
    _typed_stack(dims, T, S, HasShape{1}(), A)
2825
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
27✔
2826
    if dims == N+1
27✔
2827
        _typed_stack(:, T, S, A, (_vec_axis(A),))
4✔
2828
    else
2829
        _dim_stack(dims, T, S, A)
23✔
2830
    end
2831
end
2832
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
2✔
2833
    _dim_stack(dims, T, S, A)
2834

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

2837
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
25✔
2838
    xit = Iterators.peel(A)
48✔
2839
    nothing === xit && return _empty_stack(dims, T, S, A)
25✔
2840
    x1, xrest = xit
25✔
2841
    ax1 = _iterator_axes(x1)
25✔
2842
    N1 = length(ax1)+1
24✔
2843
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
27✔
2844

2845
    newaxis = _vec_axis(A)
21✔
2846
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
141✔
2847
    B = similar(_ensure_array(x1), T, outax...)
23✔
2848

2849
    if dims == 1
21✔
2850
        _dim_stack!(Val(1), B, x1, xrest)
13✔
2851
    elseif dims == 2
8✔
2852
        _dim_stack!(Val(2), B, x1, xrest)
4✔
2853
    else
2854
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
2855
    end
2856
    B
18✔
2857
end
2858

2859
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
2860
    before = ntuple(d -> Colon(), dims - 1)
33✔
2861
    after = ntuple(d -> Colon(), ndims(B) - dims)
49✔
2862

2863
    i = firstindex(B, dims)
21✔
2864
    copyto!(view(B, before..., i, after...), x1)
39✔
2865

2866
    for x in xrest
29✔
2867
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
2868
        i += 1
3,261✔
2869
        @inbounds copyto!(view(B, before..., i, after...), x)
6,512✔
2870
    end
3,261✔
2871
end
2872

2873
@inline function _stack_size_check(x, ax1::Tuple)
5,740✔
2874
    if _iterator_axes(x) != ax1
11,107✔
2875
        uax1 = map(UnitRange, ax1)
9✔
2876
        uaxN = map(UnitRange, axes(x))
9✔
2877
        throw(DimensionMismatch(
9✔
2878
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
2879
    end
2880
end
2881

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

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

2887

2888
## Reductions and accumulates ##
2889

2890
function isequal(A::AbstractArray, B::AbstractArray)
19,447✔
2891
    if A === B return true end
19,706✔
2892
    if axes(A) != axes(B)
34,897✔
2893
        return false
3,479✔
2894
    end
2895
    for (a, b) in zip(A, B)
31,172✔
2896
        if !isequal(a, b)
534,787✔
2897
            return false
566✔
2898
        end
2899
    end
851,967✔
2900
    return true
15,143✔
2901
end
2902

2903
function cmp(A::AbstractVector, B::AbstractVector)
307✔
2904
    for (a, b) in zip(A, B)
614✔
2905
        if !isequal(a, b)
806✔
2906
            return isless(a, b) ? -1 : 1
292✔
2907
        end
2908
    end
1,013✔
2909
    return cmp(length(A), length(B))
15✔
2910
end
2911

2912
"""
2913
    isless(A::AbstractVector, B::AbstractVector)
2914

2915
Return `true` when `A` is less than `B` in lexicographic order.
2916
"""
2917
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
298✔
2918

2919
function (==)(A::AbstractArray, B::AbstractArray)
6,478,344✔
2920
    if axes(A) != axes(B)
12,956,645✔
2921
        return false
2,901✔
2922
    end
2923
    anymissing = false
6,473,783✔
2924
    for (a, b) in zip(A, B)
12,069,319✔
2925
        eq = (a == b)
329,195,216✔
2926
        if ismissing(eq)
294,536,740✔
2927
            anymissing = true
24✔
2928
        elseif !eq
328,306,878✔
2929
            return false
444✔
2930
        end
2931
    end
651,020,903✔
2932
    return anymissing ? missing : true
6,476,468✔
2933
end
2934

2935
# _sub2ind and _ind2sub
2936
# fallbacks
2937
function _sub2ind(A::AbstractArray, I...)
761,172✔
2938
    @inline
761,172✔
2939
    _sub2ind(axes(A), I...)
1,794,843✔
2940
end
2941

2942
function _ind2sub(A::AbstractArray, ind)
390,297✔
2943
    @inline
390,297✔
2944
    _ind2sub(axes(A), ind)
390,297✔
2945
end
2946

2947
# 0-dimensional arrays and indexing with []
2948
_sub2ind(::Tuple{}) = 1
18✔
2949
_sub2ind(::DimsInteger) = 1
2✔
2950
_sub2ind(::Indices) = 1
×
2951
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
3✔
2952

2953
# Generic cases
2954
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
2,014,509,152✔
2955
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
1,912,999✔
2956
# In 1d, there's a question of whether we're doing cartesian indexing
2957
# or linear indexing. Support only the former.
2958
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
2959
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2960
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
2961
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
2962

2963
_sub2ind_recurse(::Any, L, ind) = ind
2,354,080✔
2964
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,786✔
2965
    @inline
867✔
2966
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
12,101✔
2967
end
2968
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
3,713,353✔
2969
    @inline
3,143,045✔
2970
    r1 = inds[1]
3,183,885✔
2971
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
2,019,029,104✔
2972
end
2973

2974
nextL(L, l::Integer) = L*l
2,502,454✔
2975
nextL(L, r::AbstractUnitRange) = L*length(r)
2,429,391✔
2976
nextL(L, r::Slice) = L*length(r.indices)
×
2977
offsetin(i, l::Integer) = i-1
2,014,650,316✔
2978
offsetin(i, r::AbstractUnitRange) = i-first(r)
4,223,658✔
2979

2980
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
2981
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
2,070✔
2982
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
390,282✔
2983
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
2984
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2985
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
39✔
2986

2987
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
2988
function _ind2sub_recurse(indslast::NTuple{1}, ind)
392,352✔
2989
    @inline
392,352✔
2990
    (_lookup(ind, indslast[1]),)
392,352✔
2991
end
2992
function _ind2sub_recurse(inds, ind)
738,369✔
2993
    @inline
738,369✔
2994
    r1 = inds[1]
738,369✔
2995
    indnext, f, l = _div(ind, r1)
738,369✔
2996
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
738,369✔
2997
end
2998

2999
_lookup(ind, d::Integer) = ind+1
2,070✔
3000
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
390,282✔
3001
_div(ind, d::Integer) = div(ind, d), 1, d
2,070✔
3002
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
1,472,598✔
3003

3004
# Vectorized forms
3005
function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
×
3006
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
×
3007
end
3008
_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3009
    _sub2ind_vecs(inds, I1, I...)
3010
_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3011
    _sub2ind_vecs(inds, I1, I...)
3012
function _sub2ind_vecs(inds, I::AbstractVector...)
×
3013
    I1 = I[1]
×
3014
    Iinds = axes1(I1)
×
3015
    for j = 2:length(I)
×
3016
        axes1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(axes1(I[j])))"))
×
3017
    end
×
3018
    Iout = similar(I1)
×
3019
    _sub2ind!(Iout, inds, Iinds, I)
×
3020
    Iout
×
3021
end
3022

3023
function _sub2ind!(Iout, inds, Iinds, I)
×
3024
    @noinline
×
3025
    for i in Iinds
×
3026
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3027
        Iout[i] = sub2ind_vec(inds, i, I)
×
3028
    end
×
3029
    Iout
×
3030
end
3031

3032
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3033
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3034
_sub2ind_vec(i) = ()
×
3035

3036
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3037
    M = length(ind)
×
3038
    t = ntuple(n->similar(ind),Val(N))
×
3039
    for (i,idx) in pairs(IndexLinear(), ind)
×
3040
        sub = _ind2sub(inds, idx)
×
3041
        for j = 1:N
×
3042
            t[j][i] = sub[j]
×
3043
        end
×
3044
    end
×
3045
    t
×
3046
end
3047

3048
## iteration utilities ##
3049

3050
"""
3051
    foreach(f, c...) -> Nothing
3052

3053
Call function `f` on each element of iterable `c`.
3054
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3055
any iterator is finished.
3056

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

3060
# Examples
3061
```jldoctest
3062
julia> tri = 1:3:7; res = Int[];
3063

3064
julia> foreach(x -> push!(res, x^2), tri)
3065

3066
julia> res
3067
3-element Vector{$(Int)}:
3068
  1
3069
 16
3070
 49
3071

3072
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3073
1 with a
3074
4 with b
3075
7 with c
3076
```
3077
"""
3078
foreach(f) = (f(); nothing)
2✔
3079
foreach(f, itr) = (for x in itr; f(x); end; nothing)
194,302,512✔
3080
foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
11✔
3081

3082
## map over arrays ##
3083

3084
## transform any set of dimensions
3085
## dims specifies which dimensions will be transformed. for example
3086
## dims==1:2 will call f on all slices A[:,:,...]
3087
"""
3088
    mapslices(f, A; dims)
3089

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

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

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

3099
# Examples
3100
```jldoctest
3101
julia> A = reshape(1:30,(2,5,3))
3102
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3103
[:, :, 1] =
3104
 1  3  5  7   9
3105
 2  4  6  8  10
3106

3107
[:, :, 2] =
3108
 11  13  15  17  19
3109
 12  14  16  18  20
3110

3111
[:, :, 3] =
3112
 21  23  25  27  29
3113
 22  24  26  28  30
3114

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

3117
julia> B = mapslices(f, A, dims=(1,2))
3118
1×4×3 Array{$Int, 3}:
3119
[:, :, 1] =
3120
 1  1  1  1
3121

3122
[:, :, 2] =
3123
 11  11  11  11
3124

3125
[:, :, 3] =
3126
 21  21  21  21
3127

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

3130
julia> B == stack(f2, eachslice(A, dims=3))
3131
true
3132

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

3135
julia> mapslices(g, A, dims=[1,3])
3136
1×5×1 Array{Rational{$Int}, 3}:
3137
[:, :, 1] =
3138
 1//21  3//23  1//5  7//27  9//29
3139

3140
julia> map(g, eachslice(A, dims=2))
3141
5-element Vector{Rational{$Int}}:
3142
 1//21
3143
 3//23
3144
 1//5
3145
 7//27
3146
 9//29
3147

3148
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3149
true
3150
```
3151

3152
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3153
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3154
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3155
values in the slice without affecting `A`.
3156
"""
3157
function mapslices(f, A::AbstractArray; dims)
892✔
3158
    isempty(dims) && return map(f, A)
446✔
3159

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

3170
    # Apply the function to the first slice in order to determine the next steps
3171
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3,156✔
3172
    Aslice = A[idx1...]
829✔
3173
    r1 = f(Aslice)
532✔
3174

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

3191
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3192
    din = Ref(0)
442✔
3193
    Rsize = ntuple(ndims(A)) do d
442✔
3194
        if d in dims
3,237✔
3195
            axes(res1, din[] += 1)
875✔
3196
        else
3197
            axes(A,d)
805✔
3198
        end
3199
    end
3200
    R = similar(res1, Rsize)
459✔
3201

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

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

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

3218
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
468✔
3219
    return R
442✔
3220
end
3221

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

3249
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
3,702✔
3250
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
448✔
3251

3252
## 0 arguments
3253

3254
map(f) = f()
1✔
3255

3256
## 1 argument
3257

3258
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,156✔
3259
    for (i,j) in zip(eachindex(dest),eachindex(A))
220,763,305✔
3260
        val = f(@inbounds A[j])
221,664,227✔
3261
        @inbounds dest[i] = val
132,297,422✔
3262
    end
163,757,751✔
3263
    return dest
120,128,436✔
3264
end
3265

3266
# map on collections
3267
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
41,845✔
3268

3269
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
2,629✔
3270
mapany(f, itr) = Any[f(x) for x in itr]
×
3271

3272
"""
3273
    map(f, c...) -> collection
3274

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

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

3280
# Examples
3281
```jldoctest
3282
julia> map(x -> x * 2, [1, 2, 3])
3283
3-element Vector{Int64}:
3284
 2
3285
 4
3286
 6
3287

3288
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3289
3-element Vector{Int64}:
3290
 11
3291
 22
3292
 33
3293
```
3294
"""
3295
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
403✔
3296

3297
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3298
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3299

3300
## 2 argument
3301
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
188✔
3302
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
376✔
3303
        @inbounds a, b = A[j], B[k]
120,284✔
3304
        val = f(a, b)
71,137✔
3305
        @inbounds dest[i] = val
71,137✔
3306
    end
142,086✔
3307
    return dest
188✔
3308
end
3309

3310
## N argument
3311

3312
@inline ith_all(i, ::Tuple{}) = ()
4,030✔
3313
function ith_all(i, as)
12,090✔
3314
    @_propagate_inbounds_meta
12,090✔
3315
    return (as[1][i], ith_all(i, tail(as))...)
18,930✔
3316
end
3317

3318
function map_n!(f::F, dest::AbstractArray, As) where F
46✔
3319
    idxs1 = LinearIndices(As[1])
46✔
3320
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
368✔
3321
    for i = idxs1
92✔
3322
        @inbounds I = ith_all(i, As)
6,550✔
3323
        val = f(I...)
4,030✔
3324
        @inbounds dest[i] = val
4,030✔
3325
    end
8,014✔
3326
    return dest
46✔
3327
end
3328

3329
"""
3330
    map!(function, destination, collection...)
3331

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

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

3337
# Examples
3338
```jldoctest
3339
julia> a = zeros(3);
3340

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

3343
julia> a
3344
3-element Vector{Float64}:
3345
 2.0
3346
 4.0
3347
 6.0
3348

3349
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3350
5-element Vector{$(Int)}:
3351
 101
3352
 103
3353
 105
3354
   0
3355
   0
3356
```
3357
"""
3358
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
47✔
3359
    isempty(As) && throw(ArgumentError(
47✔
3360
        """map! requires at least one "source" argument"""))
3361
    map_n!(f, dest, As)
46✔
3362
end
3363

3364
"""
3365
    map(f, A::AbstractArray...) -> N-array
3366

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

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

3372
# Examples
3373
```
3374
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3375
2×2 Matrix{Rational{$Int}}:
3376
 1//4  2//3
3377
 3//2  4//1
3378

3379
julia> map(+, [1 2; 3 4], zeros(2,1))
3380
ERROR: DimensionMismatch
3381

3382
julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1))  # iterates until 3rd is exhausted
3383
3-element Vector{Float64}:
3384
   2.0
3385
  13.0
3386
 102.0
3387
```
3388
"""
3389
map(f, iters...) = collect(Generator(f, iters...))
1,038✔
3390

3391
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3392
# (note: must not cause a dispatch loop when 1-item case is not defined)
3393
push!(A, a, b) = push!(push!(A, a), b)
998✔
3394
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
2✔
3395
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3396
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
2✔
3397

3398
## hashing AbstractArray ##
3399

3400
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3401
function hash(A::AbstractArray, h::UInt)
13,742✔
3402
    h += hash_abstractarray_seed
13,742✔
3403
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3404
    # Instead hash the tuple of firsts and lasts along each dimension
3405
    h = hash(map(first, axes(A)), h)
13,799✔
3406
    h = hash(map(last, axes(A)), h)
13,799✔
3407

3408
    # For short arrays, it's not worth doing anything complicated
3409
    if length(A) < 8192
13,799✔
3410
        for x in A
18,137✔
3411
            h = hash(x, h)
391,198✔
3412
        end
440,547✔
3413
        return h
13,738✔
3414
    end
3415

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

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

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

3437
    # Start at the last index
3438
    keyidx = last(ks)
4✔
3439
    linidx = key_to_linear[keyidx]
4✔
3440
    fibskip = prevfibskip = oneunit(linidx)
4✔
3441
    first_linear = first(LinearIndices(linear_to_key))
4✔
3442
    n = 0
4✔
3443
    while true
28,192✔
3444
        n += 1
28,192✔
3445
        # Hash the element
3446
        elt = A[keyidx]
28,192✔
3447
        h = hash(keyidx=>elt, h)
28,192✔
3448

3449
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3450
        linidx = key_to_linear[keyidx]
28,192✔
3451
        linidx < fibskip + first_linear && break
28,192✔
3452
        linidx -= fibskip
28,188✔
3453
        keyidx = linear_to_key[linidx]
28,188✔
3454

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

3465
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3466
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3467
        keyidx === nothing && break
28,188✔
3468
    end
28,188✔
3469

3470
    return h
4✔
3471
end
3472

3473
# The semantics of `collect` are weird. Better to write our own
3474
function rest(a::AbstractArray{T}, state...) where {T}
11✔
3475
    v = Vector{T}(undef, 0)
11✔
3476
    # assume only very few items are taken from the front
3477
    sizehint!(v, length(a))
11✔
3478
    return foldl(push!, Iterators.rest(a, state...), init=v)
11✔
3479
end
3480

3481

3482
## keepat! ##
3483

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

3486
function _keepat!(a::AbstractVector, inds)
11✔
3487
    local prev
11✔
3488
    i = firstindex(a)
11✔
3489
    for k in inds
19✔
3490
        if @isdefined(prev)
34✔
3491
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
27✔
3492
        end
3493
        ak = a[k] # must happen even when i==k for bounds checking
32✔
3494
        if i != k
29✔
3495
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
13✔
3496
        end
3497
        prev = k
29✔
3498
        i = nextind(a, i)
29✔
3499
    end
51✔
3500
    deleteat!(a, i:lastindex(a))
11✔
3501
    return a
6✔
3502
end
3503

3504
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
5✔
3505
    length(m) == length(a) || throw(BoundsError(a, m))
7✔
3506
    j = firstindex(a)
3✔
3507
    for i in eachindex(a, m)
5✔
3508
        @inbounds begin
20✔
3509
            if m[i]
20✔
3510
                i == j || (a[j] = a[i])
16✔
3511
                j = nextind(a, j)
9✔
3512
            end
3513
        end
3514
    end
38✔
3515
    deleteat!(a, j:lastindex(a))
3✔
3516
end
3517

3518
## 1-d circshift ##
3519
function circshift!(a::AbstractVector, shift::Integer)
1,137✔
3520
    n = length(a)
1,137✔
3521
    n == 0 && return
1,137✔
3522
    shift = mod(shift, n)
2,274✔
3523
    shift == 0 && return
1,137✔
3524
    l = lastindex(a)
695✔
3525
    reverse!(a, firstindex(a), l-shift)
695✔
3526
    reverse!(a, l-shift+1, lastindex(a))
695✔
3527
    reverse!(a)
695✔
3528
    return a
695✔
3529
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

© 2025 Coveralls, Inc