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

JuliaLang / julia / #37476

pending completion
#37476

push

local

web-flow
Ensure accurate invalidation logging data (#48982)

* Ensure accurate invalidation logging data

This modifies #48841 to restore the required logging data.
By collecting at least one additional match, we retain the possibility
of identifying at least one trigger of invalidation.

* Bump number of invalidation causes

* Update src/staticdata_utils.c

Co-authored-by: Jameson Nash <vtjnash@gmail.com>

---------

Co-authored-by: Jameson Nash <vtjnash@gmail.com>

71283 of 82556 relevant lines covered (86.35%)

34551491.63 hits per line

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

91.62
/base/abstractarray.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
## Basic functions ##
4

5
"""
6
    AbstractArray{T,N}
7

8
Supertype for `N`-dimensional arrays (or array-like types) with elements of type `T`.
9
[`Array`](@ref) and other types are subtypes of this. See the manual section on the
10
[`AbstractArray` interface](@ref man-interface-array).
11

12
See also: [`AbstractVector`](@ref), [`AbstractMatrix`](@ref), [`eltype`](@ref), [`ndims`](@ref).
13
"""
14
AbstractArray
15

16
convert(::Type{T}, a::T) where {T<:AbstractArray} = a
5,703,552✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
20,533✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
27,377✔
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,562,314✔
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}
866,185✔
76
    @inline
864,896✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
872,446✔
78
end
79

80
"""
81
    axes(A)
82

83
Return the tuple of valid indices for array `A`.
84

85
See also: [`size`](@ref), [`keys`](@ref), [`eachindex`](@ref).
86

87
# Examples
88

89
```jldoctest
90
julia> A = fill(1, (5,6,7));
91

92
julia> axes(A)
93
(Base.OneTo(5), Base.OneTo(6), Base.OneTo(7))
94
```
95
"""
96
function axes(A)
246,318,677✔
97
    @inline
146,562,761✔
98
    map(oneto, size(A))
6,087,499,852✔
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)...)
781,354✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
237,204✔
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...)
486,035✔
115
has_offset_axes(::Colon) = false
67✔
116
has_offset_axes(::Array) = false
556,280✔
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,444,224✔
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])
6,153,723,590✔
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,072✔
163
keys(a::AbstractVector) = LinearIndices(a)
39,789,854✔
164

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

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

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

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

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

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

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

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

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

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

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

210
prevind(::AbstractArray, i::Integer) = Int(i)-1
146,390✔
211
nextind(::AbstractArray, i::Integer) = Int(i)+1
154,429,667✔
212

213

214
"""
215
    eltype(type)
216

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

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

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

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

239
"""
240
    elsize(type)
241

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

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

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

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

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

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

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

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

275
Return the number of elements in the collection.
276

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

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

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

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

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

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

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

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

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

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

314
# eachindex iterates over all indices. IndexCartesian definitions are later.
315
eachindex(A::AbstractVector) = (@inline(); axes1(A))
1,078,657,855✔
316

317

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

416
julia> lastindex(rand(3,4,5), 2)
417
4
418
```
419
"""
420
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
2,239,840,688✔
421
lastindex(a, d) = (@inline; last(axes(a, d)))
3,663✔
422

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

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

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

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

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

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

446
first(a::AbstractArray) = a[first(eachindex(a))]
1,121,908✔
447

448
"""
449
    first(coll)
450

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

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

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

461
julia> first([1; 2; 3; 4])
462
1
463
```
464
"""
465
function first(itr)
2,962,487✔
466
    x = iterate(itr)
5,921,725✔
467
    x === nothing && throw(ArgumentError("collection must be non-empty"))
2,962,488✔
468
    x[1]
2,962,486✔
469
end
470

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

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

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

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

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

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

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

503
"""
504
    last(coll)
505

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

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

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

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

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

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

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

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

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

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

553
"""
554
    strides(A)
555

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

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

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

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

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

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

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

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

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

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

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

604

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

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

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

644
## Bounds checking ##
645

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

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

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

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

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

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

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

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

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

692
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index
693
function checkbounds(::Type{Bool}, A::AbstractArray, i)
123,373,249✔
694
    @inline
117,169,376✔
695
    checkindex(Bool, eachindex(IndexLinear(), A), i)
2,667,830,368✔
696
end
697
# As a special extension, allow using logical arrays that match the source array exactly
698
function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{Bool,N}) where N
88✔
699
    @inline
88✔
700
    axes(A) == axes(I)
143✔
701
end
702

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

706
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
707
"""
708
function checkbounds(A::AbstractArray, I...)
654,387,126✔
709
    @inline
209,863,031✔
710
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
654,387,588✔
711
    nothing
654,387,682✔
712
end
713

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

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

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

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

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

732
See also [`checkbounds`](@ref).
733
"""
734
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
176,195,945✔
735
    @inline
11,698,714✔
736
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
310,327,025✔
737
end
738
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
25,414✔
739
    @inline
3,563✔
740
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
29,812✔
741
end
742
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
577,849✔
743
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
×
744

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

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

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

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

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

763
julia> checkindex(Bool, 1:20, 21)
764
false
765
```
766
"""
767
checkindex(::Type{Bool}, inds::AbstractUnitRange, i) =
×
768
    throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
769
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
4,637,541✔
770
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
3,049,879✔
771
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
3,314,319,938✔
772
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
448✔
773
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
75✔
774
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
8,319,744✔
775
    @_propagate_inbounds_meta
924,312✔
776
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
334,653,547✔
777
end
778
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == axes1(I)
2✔
779
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool}) = false
1✔
780
function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
4,744✔
781
    @inline
632✔
782
    b = true
632✔
783
    for i in I
7,785✔
784
        b &= checkindex(Bool, inds, i)
6,401,884✔
785
    end
6,432,037✔
786
    b
7,194✔
787
end
788

789
# See also specializations in multidimensional
790

791
## Constructors ##
792

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

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

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

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

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

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

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

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

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

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

852
to_shape(::Tuple{}) = ()
18✔
853
to_shape(dims::Dims) = dims
5,938✔
854
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
5,224,016✔
855
# each dimension
856
to_shape(i::Int) = i
4✔
857
to_shape(i::Integer) = Int(i)
38✔
858
to_shape(r::OneTo) = Int(last(r))
42,282✔
859
to_shape(r::AbstractUnitRange) = r
196✔
860

861
"""
862
    similar(storagetype, axes)
863

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

868
**Examples**:
869

870
    similar(Array{Int}, axes(A))
871

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

878
    similar(BitArray, (axes(A, 2),))
879

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

887
"""
888
    empty(v::AbstractVector, [eltype])
889

890
Create an empty vector similar to `v`, optionally changing the `eltype`.
891

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

894
# Examples
895

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

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

906
# like empty, but should return a mutable collection, a Vector by default
907
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
217✔
908
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
60✔
909

910
"""
911
    copy!(dst, src) -> dst
912

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

919
See also [`copyto!`](@ref).
920

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

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

940
## from general iterable to any array
941

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

946
function copyto!(dest::AbstractArray, src)
4,144,968✔
947
    destiter = eachindex(dest)
4,145,028✔
948
    y = iterate(destiter)
5,518,836✔
949
    for x in src
6,635,058✔
950
        y === nothing &&
4,853,746✔
951
            throw(ArgumentError("destination has fewer elements than required"))
952
        dest[y[1]] = x
4,853,865✔
953
        y = iterate(destiter, y[2])
8,333,407✔
954
    end
7,757,027✔
955
    return dest
4,145,026✔
956
end
957

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

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

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

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

1039
"""
1040
    copyto!(dest::AbstractArray, src) -> dest
1041

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

1046
See also [`copy!`](@ref Base.copy!), [`copy`](@ref).
1047

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

1052
julia> y = zeros(7);
1053

1054
julia> copyto!(y, x);
1055

1056
julia> y
1057
7-element Vector{Float64}:
1058
 1.0
1059
 0.0
1060
 3.0
1061
 0.0
1062
 5.0
1063
 0.0
1064
 0.0
1065
```
1066
"""
1067
function copyto!(dest::AbstractArray, src::AbstractArray)
2,756,381✔
1068
    isempty(src) && return dest
2,769,892✔
1069
    if dest isa BitArray
143,468✔
1070
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1071
        return _copyto_bitarray!(dest, src)
1✔
1072
    end
1073
    src′ = unalias(dest, src)
2,800,657✔
1074
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,769,408✔
1075
end
1076

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

1083
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
2,769,408✔
1084
    isempty(src) && return dest
2,769,408✔
1085
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,769,411✔
1086
    idf, isf = first(destinds), first(srcinds)
143,466✔
1087
    Δi = idf - isf
143,466✔
1088
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,769,409✔
1089
        throw(BoundsError(dest, srcinds))
1090
    if deststyle isa IndexLinear
143,465✔
1091
        if srcstyle isa IndexLinear
138,967✔
1092
            # Single-index implementation
1093
            @inbounds for i in srcinds
5,270,462✔
1094
                dest[i + Δi] = src[i]
35,730,258✔
1095
            end
68,818,276✔
1096
        else
1097
            # Dual-index implementation
1098
            i = idf - 1
129,264✔
1099
            @inbounds for a in src
259,347✔
1100
                dest[i+=1] = a
3,168,259✔
1101
            end
6,199,653✔
1102
        end
1103
    else
1104
        iterdest, itersrc = eachindex(dest), eachindex(src)
4,498✔
1105
        if iterdest == itersrc
4,498✔
1106
            # Shared-iterator implementation
1107
            for I in iterdest
4,282✔
1108
                @inbounds dest[I] = src[I]
6,386,437✔
1109
            end
12,202,873✔
1110
        else
1111
            # Dual-iterator implementation
1112
            ret = iterate(iterdest)
4,714✔
1113
            @inbounds for a in src
4,402✔
1114
                idx, state = ret::NTuple{2,Any}
2,009,469✔
1115
                dest[idx] = a
2,009,469✔
1116
                ret = iterate(iterdest, state)
2,011,827✔
1117
            end
4,008,113✔
1118
        end
1119
    end
1120
    return dest
2,769,407✔
1121
end
1122

1123
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
20,842✔
1124
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
20,850✔
1125
end
1126

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

1133
function copyto!(dest::AbstractArray, dstart::Integer,
51,885✔
1134
               src::AbstractArray, sstart::Integer,
1135
               n::Integer)
1136
    n == 0 && return dest
51,885✔
1137
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
51,883✔
1138
        n," elements, but n should be nonnegative")))
1139
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
51,882✔
1140
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
51,894✔
1141
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
51,873✔
1142
    src′ = unalias(dest, src)
53,981✔
1143
    @inbounds for i = 0:n-1
103,734✔
1144
        dest[dstart+i] = src′[sstart+i]
2,465,193✔
1145
    end
4,878,519✔
1146
    return dest
51,867✔
1147
end
1148

1149
function copy(a::AbstractArray)
146,882✔
1150
    @_propagate_inbounds_meta
504✔
1151
    copymutable(a)
147,525✔
1152
end
1153

1154
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
2,551✔
1155
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1156
    if length(ir_dest) != length(ir_src)
2,551✔
1157
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1158
            length(ir_src)," and ",length(ir_dest),")")))
1159
    end
1160
    if length(jr_dest) != length(jr_src)
2,550✔
1161
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1162
            length(jr_src)," and ",length(jr_dest),")")))
1163
    end
1164
    @boundscheck checkbounds(B, ir_dest, jr_dest)
2,550✔
1165
    @boundscheck checkbounds(A, ir_src, jr_src)
2,550✔
1166
    A′ = unalias(B, A)
5,098✔
1167
    jdest = first(jr_dest)
2,550✔
1168
    for jsrc in jr_src
5,100✔
1169
        idest = first(ir_dest)
18,465✔
1170
        for isrc in ir_src
36,930✔
1171
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
185,656✔
1172
            idest += step(ir_dest)
185,496✔
1173
        end
352,527✔
1174
        jdest += step(jr_dest)
18,465✔
1175
    end
34,380✔
1176
    return B
2,550✔
1177
end
1178

1179
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
70,296✔
1180

1181
function copyto_axcheck!(dest, src)
43,815✔
1182
    _checkaxs(axes(dest), axes(src))
49,513✔
1183
    copyto!(dest, src)
60,735✔
1184
end
1185

1186
"""
1187
    copymutable(a)
1188

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

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

1199
julia> Base.copymutable(tup)
1200
3-element Vector{Int64}:
1201
 1
1202
 2
1203
 3
1204
```
1205
"""
1206
function copymutable(a::AbstractArray)
2,715✔
1207
    @_propagate_inbounds_meta
1,342✔
1208
    copyto!(similar(a), a)
154,110✔
1209
end
1210
copymutable(itr) = collect(itr)
1✔
1211

1212
zero(x::AbstractArray{T}) where {T} = fill!(similar(x, typeof(zero(T))), zero(T))
14,444✔
1213

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

1217
# While the definitions for IndexLinear are all simple enough to inline on their
1218
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1219
# inlining.
1220
function iterate(A::AbstractArray, state=(eachindex(A),))
110,296,499✔
1221
    y = iterate(state...)
136,482,538✔
1222
    y === nothing && return nothing
112,930,274✔
1223
    A[y[1]], (state[1], tail(y)...)
112,437,309✔
1224
end
1225

1226
isempty(a::AbstractArray) = (length(a) == 0)
2,741,891,043✔
1227

1228

1229
## range conversions ##
1230

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

1238
## unsafe/pointer conversions ##
1239

1240
# note: the following type definitions don't mean any AbstractArray is convertible to
1241
# a data Ref. they just map the array element type to the pointer type for
1242
# convenience in cases that work.
1243
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
16,989,835✔
1244
function pointer(x::AbstractArray{T}, i::Integer) where T
8,650,337✔
1245
    @inline
5,154,998✔
1246
    unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
322,431,880✔
1247
end
1248

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

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

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

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

1279
julia> getindex(A, 1)
1280
1
1281

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

1287
julia> getindex(A, 2:4)
1288
3-element Vector{Int64}:
1289
 3
1290
 2
1291
 4
1292
```
1293
"""
1294
function getindex(A::AbstractArray, I...)
96,662,799✔
1295
    @_propagate_inbounds_meta
95,973,171✔
1296
    error_if_canonical_getindex(IndexStyle(A), A, I...)
95,973,171✔
1297
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
222,694,615✔
1298
end
1299
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1300
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
156,476,069✔
1301

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

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

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

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

1324
## IndexLinear Scalar indexing: canonical method is one Int
1325
_getindex(::IndexLinear, A::AbstractVector, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))  # ambiguity resolution in case packages specialize this (to be avoided if at all possible, but see Interpolations.jl)
1,547,542✔
1326
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
×
1327
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
1,975,087✔
1328
    @inline
891,232✔
1329
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
40,156,049✔
1330
    @inbounds r = getindex(A, _to_linear_index(A, I...))
40,156,012✔
1331
    r
40,155,987✔
1332
end
1333
_to_linear_index(A::AbstractArray, i::Integer) = i
176,547✔
1334
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1,714,761✔
1335
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
289,003✔
1336
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
2,104,402✔
1337

1338
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1339
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
173,697✔
1340
    @inline
173,697✔
1341
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
173,710✔
1342
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
181,616✔
1343
    r
173,683✔
1344
end
1345
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
92,855,315✔
1346
    @_propagate_inbounds_meta
92,855,315✔
1347
    getindex(A, I...)
180,418,448✔
1348
end
1349
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
223,588✔
1350
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1351
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1352
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
5✔
1353
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1354
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1,791✔
1355
    @inline
1,791✔
1356
    J, Jrem = IteratorsMD.split(I, Val(N))
1,791✔
1357
    _to_subscript_indices(A, J, Jrem)
1,791✔
1358
end
1359
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1360
    __to_subscript_indices(A, axes(A), J, Jrem)
1361
function __to_subscript_indices(A::AbstractArray,
2✔
1362
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1363
    @inline
2✔
1364
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1365
end
1366
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
1,789✔
1367
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
24,662✔
1368
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1369
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1370
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1371
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
223,588✔
1372

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

1376
"""
1377
    setindex!(A, X, inds...)
1378
    A[inds...] = X
1379

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

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

1387
julia> setindex!(A, [10, 20], [1, 2]);
1388

1389
julia> A[[3, 4]] = [30, 40];
1390

1391
julia> A
1392
2×2 Matrix{Float64}:
1393
 10.0  30.0
1394
 20.0  40.0
1395
```
1396
"""
1397
function setindex!(A::AbstractArray, v, I...)
2,675,501✔
1398
    @_propagate_inbounds_meta
2,562,650✔
1399
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,562,650✔
1400
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
3,719,042✔
1401
end
1402
function unsafe_setindex!(A::AbstractArray, v, I...)
732✔
1403
    @inline
732✔
1404
    @inbounds r = setindex!(A, v, I...)
732✔
1405
    r
730✔
1406
end
1407

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

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

1418
## IndexLinear Scalar indexing
1419
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
233,964✔
1420
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
153,673✔
1421
    @inline
106,943✔
1422
    @boundscheck checkbounds(A, I...)
160,451✔
1423
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
160,414✔
1424
    r
160,413✔
1425
end
1426

1427
# IndexCartesian Scalar indexing
1428
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,395,888✔
1429
    @_propagate_inbounds_meta
2,395,888✔
1430
    setindex!(A, v, I...)
2,395,987✔
1431
end
1432
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
3,266✔
1433
    @inline
3,266✔
1434
    @boundscheck checkbounds(A, I...)
3,271✔
1435
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
3,261✔
1436
    r
3,261✔
1437
end
1438

1439
"""
1440
    parent(A)
1441

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

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

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

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

1467
## rudimentary aliasing detection ##
1468
"""
1469
    Base.unalias(dest, A)
1470

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

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

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

1481
See also [`Base.mightalias`](@ref).
1482
"""
1483
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
8,272,236✔
1484
unalias(dest, A::AbstractRange) = A
2,843,297✔
1485
unalias(dest, A) = A
2,612,906✔
1486

1487
"""
1488
    Base.unaliascopy(A)
1489

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

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

1510
"""
1511
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1512

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

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

1521
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1522
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1523
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1524
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1525
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
5,408,447✔
1526
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
82,742✔
1527
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1528
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
2,096✔
1529
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
83,878✔
1530

1531
"""
1532
    Base.dataids(A::AbstractArray)
1533

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

1536
Custom arrays that would like to opt-in to aliasing detection of their component
1537
parts can specialize this method to return the concatenation of the `dataids` of
1538
their component parts.  A typical definition for an array that wraps a parent is
1539
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1540
"""
1541
dataids(A::AbstractArray) = (UInt(objectid(A)),)
118,704✔
1542
dataids(A::Array) = (UInt(pointer(A)),)
10,818,445✔
1543
dataids(::AbstractRange) = ()
5,719✔
1544
dataids(x) = ()
3,802✔
1545

1546
## get (getindex with a default value) ##
1547

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

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

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

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

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

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

1588
## structured matrix methods ##
1589
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
24,389✔
1590
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
1,176✔
1591

1592
## Concatenation ##
1593
eltypeof(x) = typeof(x)
21,726✔
1594
eltypeof(x::AbstractArray) = eltype(x)
13,482✔
1595

1596
promote_eltypeof() = Bottom
×
1597
promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
35,208✔
1598

1599
promote_eltype() = Bottom
118✔
1600
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
7,626✔
1601

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

1605
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1606
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1607

1608
## cat: special cases
1609
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
317✔
1610
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
299✔
1611
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
97✔
1612
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
532✔
1613

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

1619
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
5✔
1620
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
21✔
1621

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

1627
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
792,422✔
1628
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
812,399✔
1629
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1630

1631
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
792,422✔
1632
    pos = 1
792,422✔
1633
    for k=1:Int(length(V))::Int
792,427✔
1634
        Vk = V[k]
794,091✔
1635
        p1 = pos + Int(length(Vk))::Int - 1
794,596✔
1636
        a[pos:p1] = Vk
5,713,606✔
1637
        pos = p1+1
794,091✔
1638
    end
795,760✔
1639
    a
792,422✔
1640
end
1641

1642
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
418✔
1643

1644
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
1✔
1645
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
13✔
1646

1647
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
424✔
1648
    nargs = length(A)
424✔
1649
    nrows = size(A[1], 1)
424✔
1650
    ncols = 0
424✔
1651
    dense = true
424✔
1652
    for j = 1:nargs
430✔
1653
        Aj = A[j]
866✔
1654
        if size(Aj, 1) != nrows
1,108✔
1655
            throw(ArgumentError("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1656
        end
1657
        dense &= isa(Aj,Array)
865✔
1658
        nd = ndims(Aj)
1,108✔
1659
        ncols += (nd==2 ? size(Aj,2) : 1)
1,057✔
1660
    end
1,307✔
1661
    B = similar(A[1], T, nrows, ncols)
423✔
1662
    pos = 1
423✔
1663
    if dense
423✔
1664
        for k=1:nargs
185✔
1665
            Ak = A[k]
385✔
1666
            n = length(Ak)
405✔
1667
            copyto!(B, pos, Ak, 1, n)
405✔
1668
            pos += n
385✔
1669
        end
587✔
1670
    else
1671
        for k=1:nargs
244✔
1672
            Ak = A[k]
479✔
1673
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
656✔
1674
            B[:, pos:p1] = Ak
479✔
1675
            pos = p1+1
479✔
1676
        end
479✔
1677
    end
1678
    return B
423✔
1679
end
1680

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

1684
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
772✔
1685
    nargs = length(A)
772✔
1686
    nrows = sum(a->size(a, 1), A)::Int
2,424✔
1687
    ncols = size(A[1], 2)
772✔
1688
    for j = 2:nargs
773✔
1689
        if size(A[j], 2) != ncols
830✔
1690
            throw(ArgumentError("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1691
        end
1692
    end
903✔
1693
    B = similar(A[1], T, nrows, ncols)
771✔
1694
    pos = 1
771✔
1695
    for k=1:nargs
772✔
1696
        Ak = A[k]
1,600✔
1697
        p1 = pos+size(Ak,1)::Int-1
1,658✔
1698
        B[pos:p1, :] = Ak
1,600✔
1699
        pos = p1+1
1,600✔
1700
    end
2,429✔
1701
    return B
771✔
1702
end
1703

1704
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
808,005✔
1705

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

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

1712
## cat: general case
1713

1714
# helper functions
1715
cat_size(A) = (1,)
22,322✔
1716
cat_size(A::AbstractArray) = size(A)
17,252✔
1717
cat_size(A, d) = 1
22,735✔
1718
cat_size(A::AbstractArray, d) = size(A, d)
25,008✔
1719

1720
cat_length(::Any) = 1
100✔
1721
cat_length(a::AbstractArray) = length(a)
472✔
1722

1723
cat_ndims(a) = 0
183✔
1724
cat_ndims(a::AbstractArray) = ndims(a)
684✔
1725

1726
cat_indices(A, d) = OneTo(1)
22,323✔
1727
cat_indices(A::AbstractArray, d) = axes(A, d)
18,411✔
1728

1729
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,346✔
1730
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1731
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,106✔
1732
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1733
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
1,063✔
1734
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1735

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

1751
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1752
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1753
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
598✔
1754
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
565✔
1755
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1756
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
10,569✔
1757
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1758
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
28✔
1759
    _cs(ndim, shape[1], 1)
30✔
1760
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
26✔
1761
end
1762
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
272✔
1763
    next = _cs(ndim, shape[1], nshape[1])
272✔
1764
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
272✔
1765
end
1766
@inline function _cshp(ndim::Int, dims, shape, nshape)
31,295✔
1767
    a = shape[1]
31,295✔
1768
    b = nshape[1]
31,295✔
1769
    next = dims[1] ? a + b : _cs(ndim, a, b)
32,262✔
1770
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
31,327✔
1771
end
1772

1773
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,768✔
1774
    "mismatch in dimension $d (expected $a got $b)")))
1775

1776
dims2cat(::Val{dims}) where dims = dims2cat(dims)
1,092✔
1777
function dims2cat(dims)
1,710✔
1778
    if any(≤(0), dims)
2,904✔
1779
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1780
    end
1781
    ntuple(in(dims), maximum(dims))
1,749✔
1782
end
1783

1784
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
7,310✔
1785

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

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

1802
function __cat_offset!(A, shape, catdims, offsets, x, X...)
39,563✔
1803
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1804
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
40,091✔
1805
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
39,564✔
1806
end
1807
__cat_offset!(A, shape, catdims, offsets) = A
9,467✔
1808

1809
function __cat_offset1!(A, shape, catdims, offsets, x)
39,563✔
1810
    inds = ntuple(length(offsets)) do i
39,717✔
1811
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
44,185✔
1812
    end
1813
    if x isa AbstractArray
39,561✔
1814
        A[inds...] = x
111,284✔
1815
    else
1816
        fill!(view(A, inds...), x)
23,205✔
1817
    end
1818
    newoffsets = ntuple(length(offsets)) do i
39,564✔
1819
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
46,529✔
1820
    end
1821
    return newoffsets
39,564✔
1822
end
1823

1824
"""
1825
    vcat(A...)
1826

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

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

1833
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1834

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

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

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

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

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

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

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

1868
julia> vs = [[1, 2], [3, 4], [5, 6]];
1869

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

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

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

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

1894
See also [`vcat`](@ref), [`hvcat`](@ref).
1895

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

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

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

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

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

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

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

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

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

1935
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
163✔
1936
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
323✔
1937

1938
"""
1939
    cat(A...; dims)
1940

1941
Concatenate the input arrays along the dimensions specified in `dims`.
1942

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

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

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

1957
The keyword also accepts `Val(dims)`.
1958

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

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

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

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

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

1999
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
2000
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2001
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
2002
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2003
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
2004
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
2005

2006
# 2d horizontal and vertical concatenation
2007

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

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

2021
"""
2022
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2023

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

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

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

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

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

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

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

2065
    nc = 0
655✔
2066
    for i=1:rows[1]
1,310✔
2067
        nc += size(as[i],2)
1,278✔
2068
    end
1,901✔
2069

2070
    nr = 0
655✔
2071
    a = 1
655✔
2072
    for i = 1:nbr
655✔
2073
        nr += size(as[a],1)
1,157✔
2074
        a += rows[i]
1,157✔
2075
    end
1,659✔
2076

2077
    out = similar(as[1], T, nr, nc)
655✔
2078

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

2105
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2106
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2107

2108
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,211✔
2109
    nr = length(rows)
511✔
2110
    nc = rows[1]
1,211✔
2111

2112
    a = Matrix{T}(undef, nr, nc)
1,211✔
2113
    if length(a) != length(xs)
1,211✔
2114
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2115
    end
2116
    k = 1
510✔
2117
    @inbounds for i=1:nr
1,209✔
2118
        if nc != rows[i]
3,330✔
2119
            throw(ArgumentError("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2120
        end
2121
        for j=1:nc
6,658✔
2122
            a[i,j] = xs[k]
9,273✔
2123
            k += 1
9,273✔
2124
        end
15,217✔
2125
    end
5,450✔
2126
    a
1,208✔
2127
end
2128

2129
function hvcat_fill!(a::Array, xs::Tuple)
405✔
2130
    nr, nc = size(a,1), size(a,2)
405✔
2131
    len = length(xs)
405✔
2132
    if nr*nc != len
405✔
2133
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2134
    end
2135
    k = 1
404✔
2136
    for i=1:nr
808✔
2137
        @inbounds for j=1:nc
2,238✔
2138
            a[i,j] = xs[k]
8,950✔
2139
            k += 1
8,292✔
2140
        end
15,465✔
2141
    end
1,834✔
2142
    a
404✔
2143
end
2144

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

2150
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
337✔
2151
    nr = length(rows)
337✔
2152
    nc = rows[1]
337✔
2153
    for i = 2:nr
337✔
2154
        if nc != rows[i]
706✔
2155
            throw(ArgumentError("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2156
        end
2157
    end
1,073✔
2158
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
335✔
2159
end
2160

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

2172
## N-dimensional concatenation ##
2173

2174
"""
2175
    hvncat(dim::Int, row_first, values...)
2176
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2177
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2178

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

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

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

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

2202
[:, :, 2] =
2203
 4  5  6
2204

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

2211
[:, :, 2] =
2212
 3
2213
 4
2214

2215
[:, :, 3] =
2216
 5
2217
 6
2218

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

2224
[:, :, 2] =
2225
 3  4
2226

2227
[:, :, 3] =
2228
 5  6
2229

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

2235
[:, :, 2] =
2236
 4  5  6
2237
```
2238

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

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

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

2269

2270
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2271
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2272

2273
# 1-dimensional hvncat methods
2274

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

2283
_typed_hvncat_0d_only_one() =
8✔
2284
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2285

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

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

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

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

2316
    nd = N
17✔
2317

2318
    Ndim = 0
17✔
2319
    for i ∈ eachindex(as)
18✔
2320
        Ndim += cat_size(as[i], N)
38✔
2321
        nd = max(nd, cat_ndims(as[i]))
38✔
2322
        for d ∈ 1:N - 1
32✔
2323
            cat_size(as[1], d) == cat_size(as[i], d) || throw(ArgumentError("mismatched size along axis $d in element $i"))
39✔
2324
        end
44✔
2325
    end
43✔
2326

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

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

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

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

2370
# 0-dimensional cases for balanced and unbalanced hvncat method
2371

2372
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2373
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2374

2375

2376
# balanced dimensions hvncat methods
2377

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

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

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

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

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

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

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

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

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

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

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

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

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

2521

2522
# unbalanced dimensions hvncat methods
2523

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

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

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

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

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

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

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

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

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

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

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

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

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

2613
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int}, d1::Int, d2::Int, as::Tuple{Vararg}) where {T, N}
51✔
2614
    outdims = size(A)
51✔
2615
    offsets = scratch1
51✔
2616
    inneroffsets = scratch2
51✔
2617
    for a ∈ as
51✔
2618
        if isa(a, AbstractArray)
270✔
2619
            for ai ∈ a
266✔
2620
                Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
7,046✔
2621
                A[Ai] = ai
1,888✔
2622

2623
                for j ∈ 1:N
1,888✔
2624
                    inneroffsets[j] += 1
4,152✔
2625
                    inneroffsets[j] < cat_size(a, j) && break
4,221✔
2626
                    inneroffsets[j] = 0
2,490✔
2627
                end
2,490✔
2628
            end
2,118✔
2629
        else
2630
            Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2631
            A[Ai] = a
30✔
2632
        end
2633

2634
        for j ∈ (d1, d2, 3:N...)
270✔
2635
            offsets[j] += cat_size(a, j)
599✔
2636
            offsets[j] < outdims[j] && break
518✔
2637
            offsets[j] = 0
304✔
2638
        end
304✔
2639
    end
270✔
2640
end
2641

2642
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
1,915✔
2643
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2644
    Ai = inneroffsets[1] + offsets[1] + 1
1,915✔
2645
    for j ∈ 2:nd
1,915✔
2646
        increment = inneroffsets[j] + offsets[j]
7,098✔
2647
        for k ∈ 1:j-1
14,168✔
2648
            increment *= outdims[k]
17,209✔
2649
        end
27,320✔
2650
        Ai += increment
7,098✔
2651
    end
12,281✔
2652
    Ai
1,915✔
2653
end
2654

2655
"""
2656
    stack(iter; [dims])
2657

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

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

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

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

2674
!!! compat "Julia 1.9"
2675
    This function requires at least Julia 1.9.
2676

2677
# Examples
2678
```jldoctest
2679
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2680

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

2686
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2687
true
2688

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

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

2697
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2698
true
2699

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

2706
julia> x = rand(3,4);
2707

2708
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2709
true
2710
```
2711

2712
Higher-dimensional examples:
2713

2714
```jldoctest
2715
julia> A = rand(5, 7, 11);
2716

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

2719
julia> (element = size(first(E)), container = size(E))
2720
(element = (5, 11), container = (7,))
2721

2722
julia> stack(E) |> size
2723
(5, 11, 7)
2724

2725
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2726
true
2727

2728
julia> A == stack(E; dims=2)
2729
true
2730

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

2733
julia> (element = size(first(M)), container = size(M))
2734
(element = (2, 3), container = (5, 7))
2735

2736
julia> stack(M) |> size  # keeps all dimensions
2737
(2, 3, 5, 7)
2738

2739
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2740
(35, 2, 3)
2741

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

2748
"""
2749
    stack(f, args...; [dims])
2750

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

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

2758
See also [`mapslices`](@ref), [`eachcol`](@ref).
2759

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

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

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

2780
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2781

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

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

2813
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2814
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2815
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2816

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

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

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

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

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

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

2860
    i = firstindex(B, dims)
21✔
2861
    copyto!(view(B, before..., i, after...), x1)
39✔
2862

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

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

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

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

2884

2885
## Reductions and accumulates ##
2886

2887
function isequal(A::AbstractArray, B::AbstractArray)
248,028✔
2888
    if A === B return true end
248,287✔
2889
    if axes(A) != axes(B)
492,041✔
2890
        return false
3,479✔
2891
    end
2892
    for (a, b) in zip(A, B)
487,975✔
2893
        if !isequal(a, b)
91,456,500✔
2894
            return false
566✔
2895
        end
2896
    end
182,464,105✔
2897
    return true
243,724✔
2898
end
2899

2900
function cmp(A::AbstractVector, B::AbstractVector)
323✔
2901
    for (a, b) in zip(A, B)
646✔
2902
        if !isequal(a, b)
850✔
2903
            return isless(a, b) ? -1 : 1
308✔
2904
        end
2905
    end
1,069✔
2906
    return cmp(length(A), length(B))
15✔
2907
end
2908

2909
"""
2910
    isless(A::AbstractVector, B::AbstractVector)
2911

2912
Return `true` when `A` is less than `B` in lexicographic order.
2913
"""
2914
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
314✔
2915

2916
function (==)(A::AbstractArray, B::AbstractArray)
6,558,965✔
2917
    if axes(A) != axes(B)
13,117,815✔
2918
        return false
2,988✔
2919
    end
2920
    anymissing = false
6,552,189✔
2921
    for (a, b) in zip(A, B)
12,228,205✔
2922
        eq = (a == b)
336,300,360✔
2923
        if ismissing(eq)
301,645,830✔
2924
            anymissing = true
24✔
2925
        elseif !eq
335,412,019✔
2926
            return false
2,322✔
2927
        end
2928
    end
665,150,969✔
2929
    return anymissing ? missing : true
6,555,124✔
2930
end
2931

2932
# _sub2ind and _ind2sub
2933
# fallbacks
2934
function _sub2ind(A::AbstractArray, I...)
728,386✔
2935
    @inline
728,386✔
2936
    _sub2ind(axes(A), I...)
2,104,402✔
2937
end
2938

2939
function _ind2sub(A::AbstractArray, ind)
223,589✔
2940
    @inline
223,589✔
2941
    _ind2sub(axes(A), ind)
223,589✔
2942
end
2943

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

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

2960
_sub2ind_recurse(::Any, L, ind) = ind
2,355,401✔
2961
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,790✔
2962
    @inline
867✔
2963
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
4,143✔
2964
end
2965
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
3,601,161✔
2966
    @inline
3,083,728✔
2967
    r1 = inds[1]
3,117,460✔
2968
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
2,194,624,430✔
2969
end
2970

2971
nextL(L, l::Integer) = L*l
2,452,426✔
2972
nextL(L, r::AbstractUnitRange) = L*length(r)
2,700,018✔
2973
nextL(L, r::Slice) = L*length(r.indices)
×
2974
offsetin(i, l::Integer) = i-1
2,189,653,387✔
2975
offsetin(i, r::AbstractUnitRange) = i-first(r)
4,842,176✔
2976

2977
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
2978
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
2,056✔
2979
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
223,601✔
2980
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
2981
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2982
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
12✔
2983

2984
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
2985
function _ind2sub_recurse(indslast::NTuple{1}, ind)
225,657✔
2986
    @inline
225,657✔
2987
    (_lookup(ind, indslast[1]),)
225,657✔
2988
end
2989
function _ind2sub_recurse(inds, ind)
387,394✔
2990
    @inline
387,394✔
2991
    r1 = inds[1]
387,394✔
2992
    indnext, f, l = _div(ind, r1)
387,394✔
2993
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
387,394✔
2994
end
2995

2996
_lookup(ind, d::Integer) = ind+1
2,056✔
2997
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
223,601✔
2998
_div(ind, d::Integer) = div(ind, d), 1, d
2,056✔
2999
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
770,676✔
3000

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

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

3029
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3030
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3031
_sub2ind_vec(i) = ()
×
3032

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

3045
## iteration utilities ##
3046

3047
"""
3048
    foreach(f, c...) -> Nothing
3049

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

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

3057
# Examples
3058
```jldoctest
3059
julia> tri = 1:3:7; res = Int[];
3060

3061
julia> foreach(x -> push!(res, x^2), tri)
3062

3063
julia> res
3064
3-element Vector{$(Int)}:
3065
  1
3066
 16
3067
 49
3068

3069
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3070
1 with a
3071
4 with b
3072
7 with c
3073
```
3074
"""
3075
foreach(f) = (f(); nothing)
2✔
3076
foreach(f, itr) = (for x in itr; f(x); end; nothing)
206,679,979✔
3077
foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
11✔
3078

3079
## map over arrays ##
3080

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

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

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

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

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

3104
[:, :, 2] =
3105
 11  13  15  17  19
3106
 12  14  16  18  20
3107

3108
[:, :, 3] =
3109
 21  23  25  27  29
3110
 22  24  26  28  30
3111

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

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

3119
[:, :, 2] =
3120
 11  11  11  11
3121

3122
[:, :, 3] =
3123
 21  21  21  21
3124

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

3127
julia> B == stack(f2, eachslice(A, dims=3))
3128
true
3129

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

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

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

3145
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3146
true
3147
```
3148

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

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

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

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

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

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

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

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

3215
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
467✔
3216
    return R
442✔
3217
end
3218

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

3246
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
3,702✔
3247
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
448✔
3248

3249
## 0 arguments
3250

3251
map(f) = f()
1✔
3252

3253
## 1 argument
3254

3255
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,606✔
3256
    for (i,j) in zip(eachindex(dest),eachindex(A))
236,815,196✔
3257
        val = f(@inbounds A[j])
237,677,833✔
3258
        @inbounds dest[i] = val
141,721,248✔
3259
    end
175,597,669✔
3260
    return dest
129,172,563✔
3261
end
3262

3263
# map on collections
3264
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
127,872✔
3265

3266
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
2,878✔
3267
mapany(f, itr) = Any[f(x) for x in itr]
×
3268

3269
"""
3270
    map(f, c...) -> collection
3271

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

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

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

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

3294
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3295
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3296

3297
## 2 argument
3298
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
364✔
3299
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
715✔
3300
        @inbounds a, b = A[j], B[k]
388,013✔
3301
        val = f(a, b)
338,192✔
3302
        @inbounds dest[i] = val
338,192✔
3303
    end
676,033✔
3304
    return dest
364✔
3305
end
3306

3307
## N argument
3308

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

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

3326
"""
3327
    map!(function, destination, collection...)
3328

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

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

3334
# Examples
3335
```jldoctest
3336
julia> a = zeros(3);
3337

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

3340
julia> a
3341
3-element Vector{Float64}:
3342
 2.0
3343
 4.0
3344
 6.0
3345

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

3361
"""
3362
    map(f, A::AbstractArray...) -> N-array
3363

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

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

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

3376
julia> map(+, [1 2; 3 4], zeros(2,1))
3377
ERROR: DimensionMismatch
3378

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

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

3395
## hashing AbstractArray ##
3396

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

3405
    # For short arrays, it's not worth doing anything complicated
3406
    if length(A) < 8192
14,833✔
3407
        for x in A
19,287✔
3408
            h = hash(x, h)
570,341✔
3409
        end
709,196✔
3410
        return h
14,592✔
3411
    end
3412

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

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

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

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

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

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

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

3467
    return h
4✔
3468
end
3469

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

3478

3479
## keepat! ##
3480

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

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

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

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