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

JuliaLang / julia / #37606

31 Aug 2023 03:12AM UTC coverage: 86.167% (-0.03%) from 86.2%
#37606

push

local

web-flow
Refine effects based on optimizer-derived information (#50805)

The optimizer may be able to derive information that is not available to
inference. For example, it may SROA a mutable value to derive additional
constant information. Additionally, some effects, like :consistent are
path-dependent and should ideally be scanned once all optimizations are
done. Now, there is a bit of a complication that we have generally so
far taken the position that the optimizer may do non-IPO-safe
optimizations, although in practice we never actually implemented any.
This was a sensible choice, because we weren't really doing anything
with the post-optimized IR other than feeding it into codegen anyway.
However, with irinterp and this change, there's now two consumers of
IPO-safely optimized IR. I do still think we may at some point want to
run passes that allow IPO-unsafe optimizations, but we can always add
them at the end of the pipeline.

With these changes, the effect analysis is a lot more precise. For
example, we can now derive :consistent for these functions:
```
function f1(b)
    if Base.inferencebarrier(b)
        error()
    end
    return b
end

function f3(x)
    @fastmath sqrt(x)
    return x
end
```
and we can derive `:nothrow` for this function:
```
function f2()
    if Ref(false)[]
        error()
    end
    return true
end
```

414 of 414 new or added lines in 13 files covered. (100.0%)

73383 of 85164 relevant lines covered (86.17%)

12690106.67 hits per line

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

92.66
/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
53,165✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
4,849✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
6,774✔
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,708,540✔
43

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

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

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

51
# Examples
52

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

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

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

63
# Usage note
64

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

69
```julia
70
ix = axes(v, 1)
71
ix[2:end]          # will work for eg Vector, but may fail in general
72
ix[(begin+1):end]  # works for generalized indexes
73
```
74
"""
75
function axes(A::AbstractArray{T,N}, d) where {T,N}
66,312,332✔
76
    @inline
66,310,833✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
66,318,859✔
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)
247,654,877✔
97
    @inline
121,449,609✔
98
    map(unchecked_oneto, size(A))
2,147,483,647✔
99
end
100

101
"""
102
    has_offset_axes(A)
103
    has_offset_axes(A, B, ...)
104

105
Return `true` if the indices of `A` start with something other than 1 along any axis.
106
If multiple arguments are passed, equivalent to `has_offset_axes(A) | has_offset_axes(B) | ...`.
107

108
See also [`require_one_based_indexing`](@ref).
109
"""
110
has_offset_axes(A) = _any_tuple(x->Int(first(x))::Int != 1, false, axes(A)...)
558,403✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
124,844✔
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...)
334,608✔
115
has_offset_axes(::Colon) = false
67✔
116
has_offset_axes(::Array) = false
581,432✔
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,345,558✔
129

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

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

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

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

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

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

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

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

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

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

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

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

188
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
2✔
189
keytype(A::Type{<:AbstractVector}) = Int
14,123✔
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
146,730✔
213
nextind(::AbstractArray, i::Integer) = Int(i)+1
245,897,354✔
214

215

216
"""
217
    eltype(type)
218

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

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

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

232
julia> eltype(fill(0x1, (2,2)))
233
UInt8
234
```
235
"""
236
eltype(::Type) = Any
13,836✔
237
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
3✔
238
eltype(x) = eltype(typeof(x))
5,370,314✔
239
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
2,380,779✔
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,708,012✔
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
697,751✔
272
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N
61✔
273
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
×
274

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

278
Return the number of elements in the collection.
279

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

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

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

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

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

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

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

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

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

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

317
# eachindex iterates over all indices. IndexCartesian definitions are later.
318
eachindex(A::AbstractVector) = (@inline(); axes1(A))
1,052,893,930✔
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))
146,384✔
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,392,301✔
386
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
2,147,483,647✔
387
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
34✔
388
    @inline
34✔
389
    indsA = eachindex(IndexLinear(), A)
34✔
390
    _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
69✔
391
        throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
392
    indsA
33✔
393
end
394
function _all_match_first(f::F, inds, A, B...) where F<:Function
39✔
395
    @inline
39✔
396
    (inds == f(A)) & _all_match_first(f, inds, B...)
43✔
397
end
398
_all_match_first(f::F, inds) where F<:Function = true
39✔
399

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

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

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

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

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

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

419
julia> lastindex(rand(3,4,5), 2)
420
4
421
```
422
"""
423
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
2,090,707,500✔
424
lastindex(a, d) = (@inline; last(axes(a, d)))
3,574✔
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,796,397✔
447
firstindex(a, d) = (@inline; first(axes(a, d)))
2,701✔
448

449
first(a::AbstractArray) = a[first(eachindex(a))]
365,983✔
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,749,410✔
469
    x = iterate(itr)
5,485,189✔
470
    x === nothing && throw(ArgumentError("collection must be non-empty"))
2,749,411✔
471
    x[1]
2,749,410✔
472
end
473

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

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

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

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

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

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

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

506
"""
507
    last(coll)
508

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

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

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

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

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

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

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

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

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

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

556
"""
557
    strides(A)
558

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

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

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

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

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

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

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

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

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

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

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

607
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
34✔
608
    @boundscheck checkbounds(A, I...)
37✔
609
    return true
31✔
610
end
611

612
# used to compute "end" for last index
613
function trailingsize(A, n)
1✔
614
    s = 1
1✔
615
    for i=n:ndims(A)
1✔
616
        s *= size(A,i)
1✔
617
    end
1✔
618
    return s
1✔
619
end
620
function trailingsize(inds::Indices, n)
×
621
    s = 1
×
622
    for i=n:length(inds)
×
623
        s *= length(inds[i])
×
624
    end
×
625
    return s
×
626
end
627
# This version is type-stable even if inds is heterogeneous
628
function trailingsize(inds::Indices)
×
629
    @inline
×
630
    prod(map(length, inds))
×
631
end
632

633
## Bounds checking ##
634

635
# The overall hierarchy is
636
#     `checkbounds(A, I...)` ->
637
#         `checkbounds(Bool, A, I...)` ->
638
#             `checkbounds_indices(Bool, IA, I)`, which recursively calls
639
#                 `checkindex` for each dimension
640
#
641
# See the "boundscheck" devdocs for more information.
642
#
643
# Note this hierarchy has been designed to reduce the likelihood of
644
# method ambiguities.  We try to make `checkbounds` the place to
645
# specialize on array type, and try to avoid specializations on index
646
# types; conversely, `checkindex` is intended to be specialized only
647
# on index type (especially, its last argument).
648

649
"""
650
    checkbounds(Bool, A, I...)
651

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

657
See also [`checkindex`](@ref).
658

659
# Examples
660
```jldoctest
661
julia> A = rand(3, 3);
662

663
julia> checkbounds(Bool, A, 2)
664
true
665

666
julia> checkbounds(Bool, A, 3, 4)
667
false
668

669
julia> checkbounds(Bool, A, 1:3)
670
true
671

672
julia> checkbounds(Bool, A, 1:3, 2:4)
673
false
674
```
675
"""
676
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
99,028,626✔
677
    @inline
99,028,626✔
678
    checkbounds_indices(Bool, axes(A), I)
100,461,817✔
679
end
680

681
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index
682
function checkbounds(::Type{Bool}, A::AbstractArray, i)
131,194,669✔
683
    @inline
125,094,941✔
684
    checkindex(Bool, eachindex(IndexLinear(), A), i)
2,147,483,647✔
685
end
686
# As a special extension, allow using logical arrays that match the source array exactly
687
function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{Bool,N}) where N
88✔
688
    @inline
88✔
689
    axes(A) == axes(I)
143✔
690
end
691

692
"""
693
    checkbounds(A, I...)
694

695
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
696
"""
697
function checkbounds(A::AbstractArray, I...)
898,156,696✔
698
    @inline
222,365,181✔
699
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
898,292,689✔
700
    nothing
898,291,350✔
701
end
702

703
"""
704
    checkbounds_indices(Bool, IA, I)
705

706
Return `true` if the "requested" indices in the tuple `I` fall within
707
the bounds of the "permitted" indices specified by the tuple
708
`IA`. This function recursively consumes elements of these tuples,
709
usually in a 1-for-1 fashion,
710

711
    checkbounds_indices(Bool, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
712
                                                          checkbounds_indices(Bool, IA, I)
713

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

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

721
See also [`checkbounds`](@ref).
722
"""
723
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
182,499,869✔
724
    @inline
13,828,308✔
725
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
320,983,546✔
726
end
727
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
15,176✔
728
    @inline
3,671✔
729
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
194,543✔
730
end
731
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
577,883✔
732
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
×
733

734
throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I)))
751✔
735

736
# check along a single dimension
737
"""
738
    checkindex(Bool, inds::AbstractUnitRange, index)
739

740
Return `true` if the given `index` is within the bounds of
741
`inds`. Custom types that would like to behave as indices for all
742
arrays can extend this method in order to provide a specialized bounds
743
checking implementation.
744

745
See also [`checkbounds`](@ref).
746

747
# Examples
748
```jldoctest
749
julia> checkindex(Bool, 1:20, 8)
750
true
751

752
julia> checkindex(Bool, 1:20, 21)
753
false
754
```
755
"""
756
checkindex(::Type{Bool}, inds::AbstractUnitRange, i) =
×
757
    throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
758
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
6,360,377✔
759
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
3,072,593✔
760
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
2,147,483,647✔
761
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
466✔
762
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
163✔
763
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
8,215,133✔
764
    @_propagate_inbounds_meta
928,034✔
765
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
373,943,904✔
766
end
767
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == axes1(I)
2✔
768
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool}) = false
1✔
769
function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
10,159✔
770
    @inline
5,023✔
771
    b = true
5,023✔
772
    for i in I
15,409✔
773
        b &= checkindex(Bool, inds, i)
6,249,733✔
774
    end
6,289,618✔
775
    b
12,991✔
776
end
777

778
# See also specializations in multidimensional
779

780
## Constructors ##
781

782
# default arguments to similar()
783
"""
784
    similar(array, [element_type=eltype(array)], [dims=size(array)])
785

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

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

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

798
```julia-repl
799
julia> similar(1:10, 1, 4)
800
1×4 Matrix{Int64}:
801
 4419743872  4374413872  4419743888  0
802
```
803

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

807
```julia-repl
808
julia> similar(trues(10,10), 2)
809
2-element BitVector:
810
 0
811
 0
812
```
813

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

817
```julia-repl
818
julia> similar(falses(10), Float64, 2, 4)
819
2×4 Matrix{Float64}:
820
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
821
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
822
```
823

824
See also: [`undef`](@ref), [`isassigned`](@ref).
825
"""
826
similar(a::AbstractArray{T}) where {T}                             = similar(a, T)
2,776✔
827
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
2,821✔
828
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
55,836,393✔
829
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
801✔
830
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
5,379,948✔
831
# Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
832
# thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
833
# but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
834
# define this method to convert supported axes to Ints, with the expectation that an offset array
835
# package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
836
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
148,172✔
837
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims))
5✔
838
# similar creates an Array by default
839
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N}    = Array{T,N}(undef, dims)
5,361,708✔
840

841
to_shape(::Tuple{}) = ()
400✔
842
to_shape(dims::Dims) = dims
5,472✔
843
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
6,824,192✔
844
# each dimension
845
to_shape(i::Int) = i
139✔
846
to_shape(i::Integer) = Int(i)
86✔
847
to_shape(r::OneTo) = Int(last(r))
61,118✔
848
to_shape(r::AbstractUnitRange) = r
188✔
849

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

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

857
**Examples**:
858

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

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

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

869
would create a 1-dimensional logical array whose indices match those
870
of the columns of `A`.
871
"""
872
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
14✔
873
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
394,615,175✔
874
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
394,615,268✔
875

876
"""
877
    empty(v::AbstractVector, [eltype])
878

879
Create an empty vector similar to `v`, optionally changing the `eltype`.
880

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

883
# Examples
884

885
```jldoctest
886
julia> empty([1.0, 2.0, 3.0])
887
Float64[]
888

889
julia> empty([1.0, 2.0, 3.0], String)
890
String[]
891
```
892
"""
893
empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
328✔
894

895
# like empty, but should return a mutable collection, a Vector by default
896
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
135✔
897
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
64✔
898

899
"""
900
    copy!(dst, src) -> dst
901

902
In-place [`copy`](@ref) of `src` into `dst`, discarding any pre-existing
903
elements in `dst`.
904
If `dst` and `src` are of the same type, `dst == src` should hold after
905
the call. If `dst` and `src` are multidimensional arrays, they must have
906
equal [`axes`](@ref).
907

908
See also [`copyto!`](@ref).
909

910
!!! compat "Julia 1.1"
911
    This method requires at least Julia 1.1. In Julia 1.0 this method
912
    is available from the `Future` standard library as `Future.copy!`.
913
"""
914
function copy!(dst::AbstractVector, src::AbstractVector)
11,032,357✔
915
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
25✔
916
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
917
    if length(dst) != length(src)
66,194,026✔
918
        resize!(dst, length(src))
66,193,971✔
919
    end
920
    copyto!(dst, src)
66,194,026✔
921
end
922

923
function copy!(dst::AbstractArray, src::AbstractArray)
15✔
924
    axes(dst) == axes(src) || throw(ArgumentError(
16✔
925
        "arrays must have the same axes for copy! (consider using `copyto!`)"))
926
    copyto!(dst, src)
14✔
927
end
928

929
## from general iterable to any array
930

931
# This is `Experimental.@max_methods 1 function copyto! end`, which is not
932
# defined at this point in bootstrap.
933
typeof(function copyto! end).name.max_methods = UInt8(1)
934

935
function copyto!(dest::AbstractArray, src)
3,546,303✔
936
    destiter = eachindex(dest)
3,548,494✔
937
    y = iterate(destiter)
4,695,209✔
938
    for x in src
5,803,931✔
939
        y === nothing &&
3,720,400✔
940
            throw(ArgumentError("destination has fewer elements than required"))
941
        dest[y[1]] = x
3,720,519✔
942
        y = iterate(destiter, y[2])
6,293,829✔
943
    end
5,852,726✔
944
    return dest
3,548,492✔
945
end
946

947
function copyto!(dest::AbstractArray, dstart::Integer, src)
276✔
948
    i = Int(dstart)
276✔
949
    if haslength(src) && length(dest) > 0
276✔
950
        @boundscheck checkbounds(dest, i:(i + length(src) - 1))
271✔
951
        for x in src
281✔
952
            @inbounds dest[i] = x
2,337✔
953
            i += 1
2,335✔
954
        end
2,803✔
955
    else
956
        for x in src
6✔
957
            dest[i] = x
6✔
958
            i += 1
3✔
959
        end
3✔
960
    end
961
    return dest
272✔
962
end
963

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

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

1025
## copy between abstract arrays - generally more efficient
1026
## since a single index variable can be used.
1027

1028
"""
1029
    copyto!(dest::AbstractArray, src) -> dest
1030

1031
Copy all elements from collection `src` to array `dest`, whose length must be greater than
1032
or equal to the length `n` of `src`. The first `n` elements of `dest` are overwritten,
1033
the other elements are left untouched.
1034

1035
See also [`copy!`](@ref Base.copy!), [`copy`](@ref).
1036

1037
# Examples
1038
```jldoctest
1039
julia> x = [1., 0., 3., 0., 5.];
1040

1041
julia> y = zeros(7);
1042

1043
julia> copyto!(y, x);
1044

1045
julia> y
1046
7-element Vector{Float64}:
1047
 1.0
1048
 0.0
1049
 3.0
1050
 0.0
1051
 5.0
1052
 0.0
1053
 0.0
1054
```
1055
"""
1056
function copyto!(dest::AbstractArray, src::AbstractArray)
2,737,827✔
1057
    isempty(src) && return dest
2,911,983✔
1058
    if dest isa BitArray
124,940✔
1059
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1060
        return _copyto_bitarray!(dest, src)
1✔
1061
    end
1062
    src′ = unalias(dest, src)
2,929,701✔
1063
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,911,571✔
1064
end
1065

1066
function copyto!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
×
1067
    isempty(src) && return dest
×
1068
    src′ = unalias(dest, src)
×
1069
    copyto_unaliased!(deststyle, dest, srcstyle, src′)
×
1070
end
1071

1072
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
296,949✔
1073
    isempty(src) && return dest
2,911,571✔
1074
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,911,572✔
1075
    idf, isf = first(destinds), first(srcinds)
124,782✔
1076
    Δi = idf - isf
124,782✔
1077
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,911,572✔
1078
        throw(BoundsError(dest, srcinds))
1079
    if deststyle isa IndexLinear
124,781✔
1080
        if srcstyle isa IndexLinear
120,597✔
1081
            # Single-index implementation
1082
            @inbounds for i in srcinds
5,271,406✔
1083
                dest[i + Δi] = src[i]
36,196,128✔
1084
            end
69,746,595✔
1085
        else
1086
            # Dual-index implementation
1087
            i = idf - 1
109,977✔
1088
            @inbounds for a in src
543,305✔
1089
                dest[i+=1] = a
3,553,717✔
1090
            end
6,828,383✔
1091
        end
1092
    else
1093
        iterdest, itersrc = eachindex(dest), eachindex(src)
4,184✔
1094
        if iterdest == itersrc
4,184✔
1095
            # Shared-iterator implementation
1096
            for I in iterdest
2,490✔
1097
                @inbounds dest[I] = src[I]
6,197,522✔
1098
            end
12,108,872✔
1099
        else
1100
            # Dual-iterator implementation
1101
            ret = iterate(iterdest)
5,878✔
1102
            @inbounds for a in src
4,984✔
1103
                idx, state = ret::NTuple{2,Any}
2,033,771✔
1104
                dest[idx] = a
2,033,771✔
1105
                ret = iterate(iterdest, state)
2,036,711✔
1106
            end
4,032,997✔
1107
        end
1108
    end
1109
    return dest
2,911,570✔
1110
end
1111

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

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

1122
function copyto!(dest::AbstractArray, dstart::Integer,
409,298✔
1123
               src::AbstractArray, sstart::Integer,
1124
               n::Integer)
1125
    n == 0 && return dest
409,298✔
1126
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
409,296✔
1127
        n," elements, but n should be nonnegative")))
1128
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
409,295✔
1129
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
409,307✔
1130
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
409,286✔
1131
    src′ = unalias(dest, src)
409,323✔
1132
    @inbounds for i = 0:n-1
818,560✔
1133
        dest[dstart+i] = src′[sstart+i]
20,681,155✔
1134
    end
40,953,030✔
1135
    return dest
409,280✔
1136
end
1137

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

1143
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
2,838✔
1144
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1145
    if length(ir_dest) != length(ir_src)
2,838✔
1146
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1147
            length(ir_src)," and ",length(ir_dest),")")))
1148
    end
1149
    if length(jr_dest) != length(jr_src)
2,837✔
1150
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1151
            length(jr_src)," and ",length(jr_dest),")")))
1152
    end
1153
    @boundscheck checkbounds(B, ir_dest, jr_dest)
2,837✔
1154
    @boundscheck checkbounds(A, ir_src, jr_src)
2,837✔
1155
    A′ = unalias(B, A)
5,672✔
1156
    jdest = first(jr_dest)
2,837✔
1157
    for jsrc in jr_src
5,674✔
1158
        idest = first(ir_dest)
20,033✔
1159
        for isrc in ir_src
40,066✔
1160
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
199,954✔
1161
            idest += step(ir_dest)
199,794✔
1162
        end
379,555✔
1163
        jdest += step(jr_dest)
20,033✔
1164
    end
37,229✔
1165
    return B
2,837✔
1166
end
1167

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

1170
function copyto_axcheck!(dest, src)
25,795✔
1171
    _checkaxs(axes(dest), axes(src))
191,003✔
1172
    copyto!(dest, src)
368,378✔
1173
end
1174

1175
"""
1176
    copymutable(a)
1177

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

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

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

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

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

1206
# While the definitions for IndexLinear are all simple enough to inline on their
1207
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1208
# inlining.
1209
function iterate(A::AbstractArray, state=(eachindex(A),))
111,229,784✔
1210
    y = iterate(state...)
137,851,603✔
1211
    y === nothing && return nothing
113,691,445✔
1212
    A[y[1]], (state[1], tail(y)...)
112,823,212✔
1213
end
1214

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

1217

1218
## range conversions ##
1219

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

1227
## unsafe/pointer conversions ##
1228

1229
# note: the following type definitions don't mean any AbstractArray is convertible to
1230
# a data Ref. they just map the array element type to the pointer type for
1231
# convenience in cases that work.
1232
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
92,181,673✔
1233
function pointer(x::AbstractArray{T}, i::Integer) where T
8,641,172✔
1234
    @inline
5,181,205✔
1235
    unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
374,609,024✔
1236
end
1237

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

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

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

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

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

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

1276
julia> getindex(A, 2:4)
1277
3-element Vector{Int64}:
1278
 3
1279
 2
1280
 4
1281
```
1282
"""
1283
function getindex(A::AbstractArray, I...)
96,831,766✔
1284
    @_propagate_inbounds_meta
96,493,725✔
1285
    error_if_canonical_getindex(IndexStyle(A), A, I...)
96,493,725✔
1286
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
239,362,624✔
1287
end
1288
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1289
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
250,662,134✔
1290

1291
unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
386✔
1292

1293
struct CanonicalIndexError <: Exception
1294
    func::String
1295
    type::Any
1296
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
14✔
1297
end
1298

1299
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1300
    throw(CanonicalIndexError("getindex", typeof(A)))
1301
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1302
    throw(CanonicalIndexError("getindex", typeof(A)))
1303
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
96,493,707✔
1304

1305
## Internal definitions
1306
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1307
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1308

1309
## IndexLinear Scalar indexing: canonical method is one Int
1310
_getindex(::IndexLinear, A::AbstractVector, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))  # ambiguity resolution in case packages specialize this (to be avoided if at all possible, but see Interpolations.jl)
20,132,118✔
1311
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
51✔
1312
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
2,089,675✔
1313
    @inline
1,005,817✔
1314
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
37,545,488✔
1315
    @inbounds r = getindex(A, _to_linear_index(A, I...))
37,545,434✔
1316
    r
37,545,402✔
1317
end
1318
_to_linear_index(A::AbstractArray, i::Integer) = i
179,601✔
1319
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1,787,255✔
1320
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
323,602✔
1321
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
2,173,080✔
1322

1323
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1324
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
400,475✔
1325
    @inline
400,475✔
1326
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
400,548✔
1327
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
432,120✔
1328
    r
400,401✔
1329
end
1330
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
93,530,352✔
1331
    @_propagate_inbounds_meta
93,530,352✔
1332
    getindex(A, I...)
180,806,772✔
1333
end
1334
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
416,440✔
1335
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1336
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1337
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
417✔
1338
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1339
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
80,136✔
1340
    @inline
80,136✔
1341
    J, Jrem = IteratorsMD.split(I, Val(N))
80,136✔
1342
    _to_subscript_indices(A, J, Jrem)
80,136✔
1343
end
1344
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1345
    __to_subscript_indices(A, axes(A), J, Jrem)
1346
function __to_subscript_indices(A::AbstractArray,
2✔
1347
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1348
    @inline
2✔
1349
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1350
end
1351
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
80,134✔
1352
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
29,740✔
1353
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1354
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1355
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1356
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
416,440✔
1357

1358
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1359
# function that allows dispatch on array storage
1360

1361
"""
1362
    setindex!(A, X, inds...)
1363
    A[inds...] = X
1364

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

1368
# Examples
1369
```jldoctest
1370
julia> A = zeros(2,2);
1371

1372
julia> setindex!(A, [10, 20], [1, 2]);
1373

1374
julia> A[[3, 4]] = [30, 40];
1375

1376
julia> A
1377
2×2 Matrix{Float64}:
1378
 10.0  30.0
1379
 20.0  40.0
1380
```
1381
"""
1382
function setindex!(A::AbstractArray, v, I...)
2,843,399✔
1383
    @_propagate_inbounds_meta
2,730,187✔
1384
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,730,187✔
1385
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
3,154,352✔
1386
end
1387
function unsafe_setindex!(A::AbstractArray, v, I...)
732✔
1388
    @inline
732✔
1389
    @inbounds r = setindex!(A, v, I...)
732✔
1390
    r
730✔
1391
end
1392

1393
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
7✔
1394
    throw(CanonicalIndexError("setindex!", typeof(A)))
1395
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1396
    throw(CanonicalIndexError("setindex!", typeof(A)))
1397
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
2,729,842✔
1398

1399
## Internal definitions
1400
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1401
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1402

1403
## IndexLinear Scalar indexing
1404
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
403,307✔
1405
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
196,185✔
1406
    @inline
141,605✔
1407
    @boundscheck checkbounds(A, I...)
203,864✔
1408
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
203,827✔
1409
    r
203,826✔
1410
end
1411

1412
# IndexCartesian Scalar indexing
1413
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,335,319✔
1414
    @_propagate_inbounds_meta
2,335,319✔
1415
    setindex!(A, v, I...)
2,335,418✔
1416
end
1417
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
22,752✔
1418
    @inline
22,752✔
1419
    @boundscheck checkbounds(A, I...)
22,757✔
1420
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
34,624✔
1421
    r
22,747✔
1422
end
1423

1424
"""
1425
    parent(A)
1426

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

1432
# Examples
1433
```jldoctest
1434
julia> A = [1 2; 3 4]
1435
2×2 Matrix{Int64}:
1436
 1  2
1437
 3  4
1438

1439
julia> V = view(A, 1:2, :)
1440
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1441
 1  2
1442
 3  4
1443

1444
julia> parent(V)
1445
2×2 Matrix{Int64}:
1446
 1  2
1447
 3  4
1448
```
1449
"""
1450
function parent end
1451

1452
parent(a::AbstractArray) = a
1,533✔
1453

1454
## rudimentary aliasing detection ##
1455
"""
1456
    Base.unalias(dest, A)
1457

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

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

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

1468
See also [`Base.mightalias`](@ref).
1469
"""
1470
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
8,766,394✔
1471
unalias(dest, A::AbstractRange) = A
2,716,120✔
1472
unalias(dest, A) = A
2,557,801✔
1473

1474
"""
1475
    Base.unaliascopy(A)
1476

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

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

1497
"""
1498
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1499

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

1502
By default, this simply checks if either of the arrays reference the same memory
1503
regions, as identified by their [`Base.dataids`](@ref).
1504
"""
1505
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !_isdisjoint(dataids(A), dataids(B))
6,026,307✔
1506
mightalias(x, y) = false
×
1507

1508
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1509
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1510
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1511
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
11✔
1512
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
5,912,389✔
1513
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
81,568✔
1514
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1515
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
5,858✔
1516
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
78,786✔
1517

1518
"""
1519
    Base.dataids(A::AbstractArray)
1520

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

1523
Custom arrays that would like to opt-in to aliasing detection of their component
1524
parts can specialize this method to return the concatenation of the `dataids` of
1525
their component parts.  A typical definition for an array that wraps a parent is
1526
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1527
"""
1528
dataids(A::AbstractArray) = (UInt(objectid(A)),)
352,515✔
1529
dataids(A::Array) = (UInt(pointer(A)),)
11,593,070✔
1530
dataids(::AbstractRange) = ()
21,039✔
1531
dataids(x) = ()
5,889✔
1532

1533
## get (getindex with a default value) ##
1534

1535
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1536
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1537

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

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

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

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

1572
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1573
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1574

1575
## structured matrix methods ##
1576
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
23,920✔
1577
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
5,601✔
1578

1579
## Concatenation ##
1580
eltypeof(x) = typeof(x)
21,018✔
1581
eltypeof(x::AbstractArray) = eltype(x)
13,960✔
1582

1583
promote_eltypeof() = error()
×
1584
promote_eltypeof(v1) = eltypeof(v1)
7,646✔
1585
promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
27,332✔
1586

1587
promote_eltype() = error()
×
1588
promote_eltype(v1) = eltype(v1)
5,899✔
1589
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
6,244✔
1590

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

1594
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1595
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1596

1597
## cat: special cases
1598
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
302✔
1599
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
175✔
1600
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
97✔
1601
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
469✔
1602

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

1608
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
4✔
1609
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
4✔
1610

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

1616
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
792,031✔
1617
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
814,052✔
1618
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1619

1620
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
792,031✔
1621
    pos = 1
792,030✔
1622
    for k=1:Int(length(V))::Int
792,038✔
1623
        Vk = V[k]
792,565✔
1624
        p1 = pos + Int(length(Vk))::Int - 1
792,580✔
1625
        a[pos:p1] = Vk
5,704,037✔
1626
        pos = p1+1
792,565✔
1627
    end
793,099✔
1628
    a
792,031✔
1629
end
1630

1631
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
411✔
1632

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

1640

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

1644
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
417✔
1645
    nargs = length(A)
417✔
1646
    nrows = size(A[1], 1)
417✔
1647
    ncols = 0
417✔
1648
    dense = true
417✔
1649
    for j = 1:nargs
423✔
1650
        Aj = A[j]
870✔
1651
        if size(Aj, 1) != nrows
1,113✔
1652
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1653
        end
1654
        dense &= isa(Aj,Array)
869✔
1655
        nd = ndims(Aj)
1,111✔
1656
        ncols += (nd==2 ? size(Aj,2) : 1)
1,054✔
1657
    end
1,322✔
1658
    B = similar(A[1], T, nrows, ncols)
416✔
1659
    pos = 1
416✔
1660
    if dense
416✔
1661
        for k=1:nargs
274✔
1662
            Ak = A[k]
571✔
1663
            n = length(Ak)
691✔
1664
            copyto!(B, pos, Ak, 1, n)
689✔
1665
            pos += n
571✔
1666
        end
870✔
1667
    else
1668
        for k=1:nargs
148✔
1669
            Ak = A[k]
297✔
1670
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
372✔
1671
            B[:, pos:p1] = Ak
297✔
1672
            pos = p1+1
297✔
1673
        end
297✔
1674
    end
1675
    return B
416✔
1676
end
1677

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

1681
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
309✔
1682
    nargs = length(A)
309✔
1683
    nrows = sum(a->size(a, 1), A)::Int
1,040✔
1684
    ncols = size(A[1], 2)
309✔
1685
    for j = 2:nargs
310✔
1686
        if size(A[j], 2) != ncols
379✔
1687
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1688
        end
1689
    end
450✔
1690
    B = similar(A[1], T, nrows, ncols)
308✔
1691
    pos = 1
308✔
1692
    for k=1:nargs
309✔
1693
        Ak = A[k]
679✔
1694
        p1 = pos+size(Ak,1)::Int-1
783✔
1695
        B[pos:p1, :] = Ak
679✔
1696
        pos = p1+1
679✔
1697
    end
1,050✔
1698
    return B
308✔
1699
end
1700

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

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

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

1709
## cat: general case
1710

1711
# helper functions
1712
cat_size(A) = (1,)
21,570✔
1713
cat_size(A::AbstractArray) = size(A)
16,508✔
1714
cat_size(A, d) = 1
21,983✔
1715
cat_size(A::AbstractArray, d) = size(A, d)
24,264✔
1716

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

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

1723
cat_indices(A, d) = OneTo(1)
21,571✔
1724
cat_indices(A::AbstractArray, d) = axes(A, d)
17,667✔
1725

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

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

1748
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1749
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
20✔
1750
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
433✔
1751
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
362✔
1752
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1753
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
3,019✔
1754
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1755
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
27✔
1756
    _cs(ndim, shape[1], 1)
29✔
1757
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
25✔
1758
end
1759
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
232✔
1760
    next = _cs(ndim, shape[1], nshape[1])
232✔
1761
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
232✔
1762
end
1763
@inline function _cshp(ndim::Int, dims, shape, nshape)
30,344✔
1764
    a = shape[1]
30,285✔
1765
    b = nshape[1]
30,285✔
1766
    next = dims[1] ? a + b : _cs(ndim, a, b)
30,588✔
1767
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
30,378✔
1768
end
1769

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

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

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

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

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

1799
function __cat_offset!(A, shape, catdims, offsets, x, X...)
38,067✔
1800
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1801
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
38,636✔
1802
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
38,072✔
1803
end
1804
__cat_offset!(A, shape, catdims, offsets) = A
8,803✔
1805

1806
function __cat_offset1!(A, shape, catdims, offsets, x)
38,063✔
1807
    inds = ntuple(length(offsets)) do i
38,223✔
1808
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
41,912✔
1809
    end
1810
    if x isa AbstractArray
38,063✔
1811
        A[inds...] = x
107,404✔
1812
    else
1813
        fill!(view(A, inds...), x)
22,018✔
1814
    end
1815
    newoffsets = ntuple(length(offsets)) do i
38,070✔
1816
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
42,495✔
1817
    end
1818
    return newoffsets
38,070✔
1819
end
1820

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2001
# 2d horizontal and vertical concatenation
2002

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

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

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

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

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

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

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

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

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

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

2060
    nc = 0
679✔
2061
    for i=1:rows[1]
1,358✔
2062
        nc += size(as[i],2)
1,983✔
2063
    end
1,973✔
2064

2065
    nr = 0
679✔
2066
    a = 1
679✔
2067
    for i = 1:nbr
679✔
2068
        nr += size(as[a],1)
1,471✔
2069
        a += rows[i]
1,181✔
2070
    end
1,683✔
2071

2072
    out = similar(as[1], T, nr, nc)
679✔
2073

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

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

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

2107
    a = Matrix{T}(undef, nr, nc)
1,299✔
2108
    if length(a) != length(xs)
1,299✔
2109
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2110
    end
2111
    k = 1
527✔
2112
    @inbounds for i=1:nr
2,067✔
2113
        if nc != rows[i]
3,508✔
2114
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2115
        end
2116
        for j=1:nc
7,014✔
2117
            a[i,j] = xs[k]
9,584✔
2118
            k += 1
9,584✔
2119
        end
15,661✔
2120
    end
5,718✔
2121
    a
1,296✔
2122
end
2123

2124
function hvcat_fill!(a::Array, xs::Tuple)
552✔
2125
    nr, nc = size(a,1), size(a,2)
552✔
2126
    len = length(xs)
552✔
2127
    if nr*nc != len
552✔
2128
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2129
    end
2130
    k = 1
551✔
2131
    for i=1:nr
1,102✔
2132
        @inbounds for j=1:nc
2,918✔
2133
            a[i,j] = xs[k]
9,676✔
2134
            k += 1
8,974✔
2135
        end
16,489✔
2136
    end
2,367✔
2137
    a
551✔
2138
end
2139

2140
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
175✔
2141
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
62✔
2142
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2143
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
3✔
2144

2145
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
400✔
2146
    nr = length(rows)
400✔
2147
    nc = rows[1]
400✔
2148
    for i = 2:nr
400✔
2149
        if nc != rows[i]
788✔
2150
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2151
        end
2152
    end
1,174✔
2153
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
398✔
2154
end
2155

2156
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T
72✔
2157
    nbr = length(rows)  # number of block rows
72✔
2158
    rs = Vector{Any}(undef, nbr)
72✔
2159
    a = 1
72✔
2160
    for i = 1:nbr
72✔
2161
        rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...)
275✔
2162
        a += rows[i]
214✔
2163
    end
356✔
2164
    T[rs...;]
72✔
2165
end
2166

2167
## N-dimensional concatenation ##
2168

2169
"""
2170
    hvncat(dim::Int, row_first, values...)
2171
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2172
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2173

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

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

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

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

2197
[:, :, 2] =
2198
 4  5  6
2199

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

2206
[:, :, 2] =
2207
 3
2208
 4
2209

2210
[:, :, 3] =
2211
 5
2212
 6
2213

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

2219
[:, :, 2] =
2220
 3  4
2221

2222
[:, :, 3] =
2223
 5  6
2224

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

2230
[:, :, 2] =
2231
 4  5  6
2232
```
2233

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

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

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

2264

2265
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2266
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2267

2268
# 1-dimensional hvncat methods
2269

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

2278
_typed_hvncat_0d_only_one() =
8✔
2279
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2280

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

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

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

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

2311
    nd = N
17✔
2312

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

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

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

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

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

2365
# 0-dimensional cases for balanced and unbalanced hvncat method
2366

2367
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2368
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2369

2370

2371
# balanced dimensions hvncat methods
2372

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

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

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

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

2431
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
90✔
2432
    # function barrier after calculating the max is necessary for high performance
2433
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
90✔
2434
    return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
124✔
2435
end
2436

2437
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
90✔
2438
    length(as) > 0 ||
90✔
2439
        throw(ArgumentError("must have at least one element"))
2440
    all(>(0), dims) ||
122✔
2441
        throw(ArgumentError("`dims` argument must contain positive integers"))
2442

2443
    d1 = row_first ? 2 : 1
58✔
2444
    d2 = row_first ? 1 : 2
58✔
2445

2446
    outdims = zeros(Int, N)
203✔
2447

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

2469
    # discover number of rows or columns
2470
    for i ∈ 1:dims[d1]
104✔
2471
        outdims[d1] += cat_size(as[i], d1)
140✔
2472
    end
164✔
2473

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

2508
    outlen = prod(outdims)
72✔
2509
    elementcount == outlen ||
36✔
2510
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2511

2512
    # copy into final array
2513
    A = cat_similar(as[1], T, outdims)
36✔
2514
    # @assert all(==(0), currentdims)
2515
    outdims .= 0
108✔
2516
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
36✔
2517
    return A
36✔
2518
end
2519

2520

2521
# unbalanced dimensions hvncat methods
2522

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

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

2535
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
107✔
2536
    length(as) > 0 ||
107✔
2537
        throw(ArgumentError("must have at least one element"))
2538
    all(>(0), tuple((shape...)...)) ||
147✔
2539
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2540

2541
    d1 = row_first ? 2 : 1
67✔
2542
    d2 = row_first ? 1 : 2
67✔
2543

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

2559
    elementcount = 0
64✔
2560
    for i ∈ eachindex(as)
64✔
2561
        elementcount += cat_length(as[i])
355✔
2562
        wasstartblock = false
313✔
2563
        for d ∈ 1:N
313✔
2564
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
907✔
2565
            dsize = cat_size(as[i], ad)
1,048✔
2566
            blockcounts[d] += 1
907✔
2567

2568
            if d == 1 || i == 1 || wasstartblock
1,501✔
2569
                currentdims[d] += dsize
623✔
2570
            elseif dsize != cat_size(as[i - 1], ad)
302✔
2571
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
8✔
2572
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2573
            end
2574

2575
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
899✔
2576

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

2595
    outlen = prod(outdims)
30✔
2596
    elementcount == outlen ||
15✔
2597
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2598

2599
    if row_first
15✔
2600
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2601
    end
2602

2603
    # @assert all(==(0), currentdims)
2604
    # @assert all(==(0), blockcounts)
2605

2606
    # copy into final array
2607
    A = cat_similar(as[1], T, outdims)
15✔
2608
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
15✔
2609
    return A
15✔
2610
end
2611

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

2630
                @inbounds for j ∈ 1:N
1,888✔
2631
                    inneroffsets[j] += 1
4,152✔
2632
                    inneroffsets[j] < cat_size(a, j) && break
4,221✔
2633
                    inneroffsets[j] = 0
2,490✔
2634
                end
2,490✔
2635
            end
2,118✔
2636
        else
2637
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2638
            A[Ai] = a
30✔
2639
        end
2640

2641
        @inbounds for j ∈ (d1, d2, 3:N...)
270✔
2642
            offsets[j] += cat_size(a, j)
599✔
2643
            offsets[j] < outdims[j] && break
518✔
2644
            offsets[j] = 0
304✔
2645
        end
304✔
2646
    end
270✔
2647
end
2648

2649
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
1,915✔
2650
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2651
    Ai = inneroffsets[1] + offsets[1] + 1
1,915✔
2652
    for j ∈ 2:nd
1,915✔
2653
        increment = inneroffsets[j] + offsets[j]
7,098✔
2654
        for k ∈ 1:j-1
14,168✔
2655
            increment *= outdims[k]
17,209✔
2656
        end
27,320✔
2657
        Ai += increment
7,098✔
2658
    end
12,281✔
2659
    Ai
1,915✔
2660
end
2661

2662
"""
2663
    stack(iter; [dims])
2664

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

2668
By default the axes of the elements are placed first,
2669
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2670
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2671

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

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

2681
!!! compat "Julia 1.9"
2682
    This function requires at least Julia 1.9.
2683

2684
# Examples
2685
```jldoctest
2686
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2687

2688
julia> mat = stack(vecs)
2689
2×3 Matrix{Float32}:
2690
 1.0  30.0  500.0
2691
 2.0  40.0  600.0
2692

2693
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2694
true
2695

2696
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2697
true
2698

2699
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2700
2×4 Matrix{Int64}:
2701
  1   2   3   4
2702
 10  11  12  13
2703

2704
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2705
true
2706

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

2713
julia> x = rand(3,4);
2714

2715
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2716
true
2717
```
2718

2719
Higher-dimensional examples:
2720

2721
```jldoctest
2722
julia> A = rand(5, 7, 11);
2723

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

2726
julia> (element = size(first(E)), container = size(E))
2727
(element = (5, 11), container = (7,))
2728

2729
julia> stack(E) |> size
2730
(5, 11, 7)
2731

2732
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2733
true
2734

2735
julia> A == stack(E; dims=2)
2736
true
2737

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

2740
julia> (element = size(first(M)), container = size(M))
2741
(element = (2, 3), container = (5, 7))
2742

2743
julia> stack(M) |> size  # keeps all dimensions
2744
(2, 3, 5, 7)
2745

2746
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2747
(35, 2, 3)
2748

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

2755
"""
2756
    stack(f, args...; [dims])
2757

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

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

2765
See also [`mapslices`](@ref), [`eachcol`](@ref).
2766

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

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

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

2787
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2788

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

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

2820
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2821
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2822
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2823

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

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

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

2849
    newaxis = _vec_axis(A)
21✔
2850
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
141✔
2851
    B = similar(_ensure_array(x1), T, outax...)
23✔
2852

2853
    if dims == 1
21✔
2854
        _dim_stack!(Val(1), B, x1, xrest)
13✔
2855
    elseif dims == 2
8✔
2856
        _dim_stack!(Val(2), B, x1, xrest)
4✔
2857
    else
2858
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
2859
    end
2860
    B
18✔
2861
end
2862

2863
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
2864
    before = ntuple(d -> Colon(), dims - 1)
33✔
2865
    after = ntuple(d -> Colon(), ndims(B) - dims)
49✔
2866

2867
    i = firstindex(B, dims)
21✔
2868
    copyto!(view(B, before..., i, after...), x1)
40✔
2869

2870
    for x in xrest
29✔
2871
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
2872
        i += 1
3,261✔
2873
        @inbounds copyto!(view(B, before..., i, after...), x)
6,415✔
2874
    end
3,261✔
2875
end
2876

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

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

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

2891

2892
## Reductions and accumulates ##
2893

2894
function isequal(A::AbstractArray, B::AbstractArray)
246,498✔
2895
    if A === B return true end
246,747✔
2896
    if axes(A) != axes(B)
489,602✔
2897
        return false
2,878✔
2898
    end
2899
    for (a, b) in zip(A, B)
486,169✔
2900
        if !isequal(a, b)
91,321,256✔
2901
            return false
430✔
2902
        end
2903
    end
182,195,322✔
2904
    return true
242,941✔
2905
end
2906

2907
function cmp(A::AbstractVector, B::AbstractVector)
313✔
2908
    for (a, b) in zip(A, B)
626✔
2909
        if !isequal(a, b)
746✔
2910
            return isless(a, b) ? -1 : 1
298✔
2911
        end
2912
    end
881✔
2913
    return cmp(length(A), length(B))
15✔
2914
end
2915

2916
"""
2917
    isless(A::AbstractVector, B::AbstractVector)
2918

2919
Return `true` when `A` is less than `B` in lexicographic order.
2920
"""
2921
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
304✔
2922

2923
function (==)(A::AbstractArray, B::AbstractArray)
6,568,226✔
2924
    if axes(A) != axes(B)
13,133,231✔
2925
        return false
3,571✔
2926
    end
2927
    anymissing = false
6,553,667✔
2928
    for (a, b) in zip(A, B)
12,243,134✔
2929
        eq = (a == b)
336,086,624✔
2930
        if ismissing(eq)
301,561,005✔
2931
            anymissing = true
24✔
2932
        elseif !eq
335,198,245✔
2933
            return false
2,671✔
2934
        end
2935
    end
664,715,553✔
2936
    return anymissing ? missing : true
6,562,199✔
2937
end
2938

2939
# _sub2ind and _ind2sub
2940
# fallbacks
2941
function _sub2ind(A::AbstractArray, I...)
786,393✔
2942
    @inline
786,393✔
2943
    _sub2ind(axes(A), I...)
2,173,080✔
2944
end
2945

2946
function _ind2sub(A::AbstractArray, ind)
416,441✔
2947
    @inline
416,441✔
2948
    _ind2sub(axes(A), ind)
416,441✔
2949
end
2950

2951
# 0-dimensional arrays and indexing with []
2952
_sub2ind(::Tuple{}) = 1
18✔
2953
_sub2ind(::DimsInteger) = 1
2✔
2954
_sub2ind(::Indices) = 1
×
2955
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
5✔
2956

2957
# Generic cases
2958
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
2,147,483,647✔
2959
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
2,291,236✔
2960
# In 1d, there's a question of whether we're doing cartesian indexing
2961
# or linear indexing. Support only the former.
2962
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
2963
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2964
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
2965
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
2966

2967
_sub2ind_recurse(::Any, L, ind) = ind
1,298,041✔
2968
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,789✔
2969
    @inline
867✔
2970
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
12,142✔
2971
end
2972
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
2,682,134✔
2973
    @inline
2,102,493✔
2974
    r1 = inds[1]
2,143,103✔
2975
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
2,147,483,647✔
2976
end
2977

2978
nextL(L, l::Integer) = L*l
1,495,453✔
2979
nextL(L, r::AbstractUnitRange) = L*length(r)
2,802,496✔
2980
nextL(L, r::Slice) = L*length(r.indices)
×
2981
offsetin(i, l::Integer) = i-1
2,147,483,647✔
2982
offsetin(i, r::AbstractUnitRange) = i-first(r)
4,956,938✔
2983

2984
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
2985
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
2,047✔
2986
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
416,426✔
2987
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
2988
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2989
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
39✔
2990

2991
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
2992
function _ind2sub_recurse(indslast::NTuple{1}, ind)
418,473✔
2993
    @inline
418,473✔
2994
    (_lookup(ind, indslast[1]),)
418,473✔
2995
end
2996
function _ind2sub_recurse(inds, ind)
764,362✔
2997
    @inline
764,362✔
2998
    r1 = inds[1]
764,362✔
2999
    indnext, f, l = _div(ind, r1)
764,362✔
3000
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
764,362✔
3001
end
3002

3003
_lookup(ind, d::Integer) = ind+1
2,047✔
3004
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
416,426✔
3005
_div(ind, d::Integer) = div(ind, d), 1, d
2,047✔
3006
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
1,524,630✔
3007

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

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

3036
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3037
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3038
_sub2ind_vec(i) = ()
×
3039

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

3052
## iteration utilities ##
3053

3054
"""
3055
    foreach(f, c...) -> Nothing
3056

3057
Call function `f` on each element of iterable `c`.
3058
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3059
any iterator is finished.
3060

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

3064
# Examples
3065
```jldoctest
3066
julia> tri = 1:3:7; res = Int[];
3067

3068
julia> foreach(x -> push!(res, x^2), tri)
3069

3070
julia> res
3071
3-element Vector{$(Int)}:
3072
  1
3073
 16
3074
 49
3075

3076
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3077
1 with a
3078
4 with b
3079
7 with c
3080
```
3081
"""
3082
foreach(f) = (f(); nothing)
2✔
3083
foreach(f, itr) = (for x in itr; f(x); end; nothing)
438,969,586✔
3084
foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
11✔
3085

3086
## map over arrays ##
3087

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

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

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

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

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

3111
[:, :, 2] =
3112
 11  13  15  17  19
3113
 12  14  16  18  20
3114

3115
[:, :, 3] =
3116
 21  23  25  27  29
3117
 22  24  26  28  30
3118

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

3121
julia> B = mapslices(f, A, dims=(1,2))
3122
1×4×3 Array{$Int, 3}:
3123
[:, :, 1] =
3124
 1  1  1  1
3125

3126
[:, :, 2] =
3127
 11  11  11  11
3128

3129
[:, :, 3] =
3130
 21  21  21  21
3131

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

3134
julia> B == stack(f2, eachslice(A, dims=3))
3135
true
3136

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

3139
julia> mapslices(g, A, dims=[1,3])
3140
1×5×1 Array{Rational{$Int}, 3}:
3141
[:, :, 1] =
3142
 1//21  3//23  1//5  7//27  9//29
3143

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

3152
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3153
true
3154
```
3155

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

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

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

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

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

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

3211
    # That skips the first element, which we already have:
3212
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
2,563✔
3213
    concatenate_setindex!(R, res1, ridx...)
455✔
3214

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

3222
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
459✔
3223
    return R
442✔
3224
end
3225

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

3253
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
3,702✔
3254
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
448✔
3255

3256
## 0 arguments
3257

3258
map(f) = f()
1✔
3259

3260
## 1 argument
3261

3262
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,681✔
3263
    for (i,j) in zip(eachindex(dest),eachindex(A))
252,745,882✔
3264
        val = f(@inbounds A[j])
268,507,858✔
3265
        @inbounds dest[i] = val
156,709,165✔
3266
    end
196,386,102✔
3267
    return dest
135,915,884✔
3268
end
3269

3270
# map on collections
3271
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
142,695✔
3272

3273
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
2,984✔
3274
mapany(f, itr) = Any[f(x) for x in itr]
×
3275

3276
"""
3277
    map(f, c...) -> collection
3278

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

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

3284
# Examples
3285
```jldoctest
3286
julia> map(x -> x * 2, [1, 2, 3])
3287
3-element Vector{Int64}:
3288
 2
3289
 4
3290
 6
3291

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

3301
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3302
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3303

3304
## 2 argument
3305
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
322✔
3306
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
631✔
3307
        @inbounds a, b = A[j], B[k]
387,042✔
3308
        val = f(a, b)
337,832✔
3309
        @inbounds dest[i] = val
337,832✔
3310
    end
675,355✔
3311
    return dest
322✔
3312
end
3313

3314
## N argument
3315

3316
@inline ith_all(i, ::Tuple{}) = ()
4,030✔
3317
function ith_all(i, as)
12,090✔
3318
    @_propagate_inbounds_meta
12,090✔
3319
    return (as[1][i], ith_all(i, tail(as))...)
18,930✔
3320
end
3321

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

3333
"""
3334
    map!(function, destination, collection...)
3335

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

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

3341
# Examples
3342
```jldoctest
3343
julia> a = zeros(3);
3344

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

3347
julia> a
3348
3-element Vector{Float64}:
3349
 2.0
3350
 4.0
3351
 6.0
3352

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

3368
"""
3369
    map(f, A::AbstractArray...) -> N-array
3370

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

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

3376
# Examples
3377
```
3378
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3379
2×2 Matrix{Rational{$Int}}:
3380
 1//4  2//3
3381
 3//2  4//1
3382

3383
julia> map(+, [1 2; 3 4], zeros(2,1))
3384
ERROR: DimensionMismatch
3385

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

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

3402
## hashing AbstractArray ##
3403

3404
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3405
function hash(A::AbstractArray, h::UInt)
12,897✔
3406
    h += hash_abstractarray_seed
12,897✔
3407
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3408
    # Instead hash the tuple of firsts and lasts along each dimension
3409
    h = hash(map(first, axes(A)), h)
13,150✔
3410
    h = hash(map(last, axes(A)), h)
13,150✔
3411

3412
    # For short arrays, it's not worth doing anything complicated
3413
    if length(A) < 8192
13,150✔
3414
        for x in A
16,713✔
3415
            h = hash(x, h)
555,723✔
3416
        end
691,978✔
3417
        return h
12,893✔
3418
    end
3419

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

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

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

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

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

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

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

3474
    return h
4✔
3475
end
3476

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

3485

3486
## keepat! ##
3487

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

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

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

3522
## 1-d circshift ##
3523
function circshift!(a::AbstractVector, shift::Integer)
1,137✔
3524
    n = length(a)
1,137✔
3525
    n == 0 && return
1,137✔
3526
    shift = mod(shift, n)
2,274✔
3527
    shift == 0 && return
1,137✔
3528
    l = lastindex(a)
887✔
3529
    reverse!(a, firstindex(a), l-shift)
887✔
3530
    reverse!(a, l-shift+1, lastindex(a))
887✔
3531
    reverse!(a)
887✔
3532
    return a
887✔
3533
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc