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

JuliaLang / julia / #37596

pending completion
#37596

push

local

web-flow
🤖 [master] Bump the Pkg stdlib from 2c04d5a98 to b044bf6a2 (#50851)

Co-authored-by: Dilum Aluthge <dilum@aluthge.com>

71913 of 84418 relevant lines covered (85.19%)

32144286.87 hits per line

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

92.09
/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
52,596✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
5,316✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
6,699✔
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,420,735✔
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}
803,148✔
76
    @inline
801,690✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
809,645✔
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)
144,875,944✔
97
    @inline
112,394,763✔
98
    map(unchecked_oneto, size(A))
5,337,406,792✔
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)...)
453,299✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
161,697✔
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...)
396,807✔
115
has_offset_axes(::Colon) = false
67✔
116
has_offset_axes(::Array) = false
634,067✔
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,348,715✔
129

130
# Performance optimization: get rid of a branch on `d` in `axes(A, d)`
131
# for d=1. 1d arrays are heavily used, and the first dimension comes up
132
# in other applications.
133
axes1(A::AbstractArray{<:Any,0}) = OneTo(1)
×
134
axes1(A::AbstractArray) = (@inline; axes(A)[1])
4,664,271,616✔
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))
28,961✔
163
keys(a::AbstractVector) = LinearIndices(a)
45,775,031✔
164

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

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

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

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

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

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

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

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

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

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

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

212
prevind(::AbstractArray, i::Integer) = Int(i)-1
137,353✔
213
nextind(::AbstractArray, i::Integer) = Int(i)+1
184,306,850✔
214

215

216
"""
217
    eltype(type)
218

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

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

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

232
julia> eltype(fill(0x1, (2,2)))
233
UInt8
234
```
235
"""
236
eltype(::Type) = Any
13,984✔
237
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
3✔
238
eltype(x) = eltype(typeof(x))
4,389,484✔
239
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
2,370,928✔
240

241
"""
242
    elsize(type)
243

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

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

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

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

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

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

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

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

278
Return the number of elements in the collection.
279

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

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

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

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

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

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

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

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

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

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

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

320

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

449
first(a::AbstractArray) = a[first(eachindex(a))]
1,310,315✔
450

451
"""
452
    first(coll)
453

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

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

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

464
julia> first([1; 2; 3; 4])
465
1
466
```
467
"""
468
function first(itr)
2,967,846✔
469
    x = iterate(itr)
5,932,401✔
470
    x === nothing && throw(ArgumentError("collection must be non-empty"))
2,967,847✔
471
    x[1]
2,967,845✔
472
end
473

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

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

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

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

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

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

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

506
"""
507
    last(coll)
508

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

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

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

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

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

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

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

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

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

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

556
"""
557
    strides(A)
558

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

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

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

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

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

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

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

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

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

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

603
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
296,566✔
604
size_to_strides(s, d) = (s,)
107✔
605
size_to_strides(s) = ()
×
606

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

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

633
## Bounds checking ##
634

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

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

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

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

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

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

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

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

672
julia> checkbounds(Bool, A, 1:3, 2:4)
673
false
674
```
675
"""
676
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
96,866,640✔
677
    @inline
96,866,640✔
678
    checkbounds_indices(Bool, axes(A), I)
97,272,173✔
679
end
680

681
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index
682
function checkbounds(::Type{Bool}, A::AbstractArray, i)
54,234,719✔
683
    @inline
46,621,200✔
684
    checkindex(Bool, eachindex(IndexLinear(), A), i)
2,558,092,768✔
685
end
686
# As a special extension, allow using logical arrays that match the source array exactly
687
function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{Bool,N}) where N
88✔
688
    @inline
88✔
689
    axes(A) == axes(I)
143✔
690
end
691

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

695
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
696
"""
697
function checkbounds(A::AbstractArray, I...)
589,856,402✔
698
    @inline
141,751,757✔
699
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
589,959,134✔
700
    nothing
589,958,539✔
701
end
702

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

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

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

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

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

721
See also [`checkbounds`](@ref).
722
"""
723
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
171,623,133✔
724
    @inline
6,431,388✔
725
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
304,529,120✔
726
end
727
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
19,703✔
728
    @inline
3,665✔
729
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
236,601✔
730
end
731
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
577,847✔
732
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
×
733

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

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

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

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

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

752
julia> checkindex(Bool, 1:20, 21)
753
false
754
```
755
"""
756
checkindex(::Type{Bool}, inds::AbstractUnitRange, i) =
×
757
    throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
758
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
6,056,895✔
759
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
3,049,778✔
760
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
3,187,366,137✔
761
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
464✔
762
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
65✔
763
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
8,214,269✔
764
    @_propagate_inbounds_meta
893,079✔
765
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
324,680,483✔
766
end
767
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == axes1(I)
2✔
768
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool}) = false
1✔
769
function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
4,448✔
770
    @inline
500✔
771
    b = true
500✔
772
    for i in I
6,819✔
773
        b &= checkindex(Bool, inds, i)
6,208,260✔
774
    end
6,214,468✔
775
    b
6,434✔
776
end
777

778
# See also specializations in multidimensional
779

780
## Constructors ##
781

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

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

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

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

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

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

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

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

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

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

841
to_shape(::Tuple{}) = ()
18✔
842
to_shape(dims::Dims) = dims
5,419✔
843
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
6,721,270✔
844
# each dimension
845
to_shape(i::Int) = i
33✔
846
to_shape(i::Integer) = Int(i)
41✔
847
to_shape(r::OneTo) = Int(last(r))
40,667✔
848
to_shape(r::AbstractUnitRange) = r
188✔
849

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

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

857
**Examples**:
858

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

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

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

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

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

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

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

883
# Examples
884

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

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

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

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

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

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

910
!!! compat "Julia 1.1"
911
    This method requires at least Julia 1.1. In Julia 1.0 this method
912
    is available from the `Future` standard library as `Future.copy!`.
913
"""
914
function copy!(dst::AbstractVector, src::AbstractVector)
5,877,335✔
915
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
50✔
916
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
917
    if length(dst) != length(src)
35,263,769✔
918
        resize!(dst, length(src))
35,263,689✔
919
    end
920
    copyto!(dst, src)
35,263,769✔
921
end
922

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

929
## from general iterable to any array
930

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

935
function copyto!(dest::AbstractArray, src)
3,877,247✔
936
    destiter = eachindex(dest)
3,879,436✔
937
    y = iterate(destiter)
5,257,294✔
938
    for x in src
6,360,465✔
939
        y === nothing &&
4,941,652✔
940
            throw(ArgumentError("destination has fewer elements than required"))
941
        dest[y[1]] = x
4,941,771✔
942
        y = iterate(destiter, y[2])
8,505,190✔
943
    end
7,964,326✔
944
    return dest
3,879,434✔
945
end
946

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

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

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

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

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

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

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

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

1041
julia> y = zeros(7);
1042

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

1045
julia> y
1046
7-element Vector{Float64}:
1047
 1.0
1048
 0.0
1049
 3.0
1050
 0.0
1051
 5.0
1052
 0.0
1053
 0.0
1054
```
1055
"""
1056
function copyto!(dest::AbstractArray, src::AbstractArray)
2,745,199✔
1057
    isempty(src) && return dest
2,758,279✔
1058
    if dest isa BitArray
132,309✔
1059
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1060
        return _copyto_bitarray!(dest, src)
1✔
1061
    end
1062
    src′ = unalias(dest, src)
2,783,313✔
1063
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,757,870✔
1064
end
1065

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

1072
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
143,280✔
1073
    isempty(src) && return dest
2,757,870✔
1074
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,757,871✔
1075
    idf, isf = first(destinds), first(srcinds)
132,308✔
1076
    Δi = idf - isf
132,308✔
1077
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,757,871✔
1078
        throw(BoundsError(dest, srcinds))
1079
    if deststyle isa IndexLinear
132,307✔
1080
        if srcstyle isa IndexLinear
128,214✔
1081
            # Single-index implementation
1082
            @inbounds for i in srcinds
5,269,222✔
1083
                dest[i + Δi] = src[i]
35,564,789✔
1084
            end
68,488,634✔
1085
        else
1086
            # Dual-index implementation
1087
            i = idf - 1
118,653✔
1088
            @inbounds for a in src
238,285✔
1089
                dest[i+=1] = a
1,927,789✔
1090
            end
3,729,044✔
1091
        end
1092
    else
1093
        iterdest, itersrc = eachindex(dest), eachindex(src)
4,093✔
1094
        if iterdest == itersrc
4,093✔
1095
            # Shared-iterator implementation
1096
            for I in iterdest
2,308✔
1097
                @inbounds dest[I] = src[I]
6,190,760✔
1098
            end
12,101,957✔
1099
        else
1100
            # Dual-iterator implementation
1101
            ret = iterate(iterdest)
5,878✔
1102
            @inbounds for a in src
4,984✔
1103
                idx, state = ret::NTuple{2,Any}
2,033,771✔
1104
                dest[idx] = a
2,033,771✔
1105
                ret = iterate(iterdest, state)
2,036,711✔
1106
            end
4,032,997✔
1107
        end
1108
    end
1109
    return dest
2,757,869✔
1110
end
1111

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

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

1122
function copyto!(dest::AbstractArray, dstart::Integer,
405,953✔
1123
               src::AbstractArray, sstart::Integer,
1124
               n::Integer)
1125
    n == 0 && return dest
405,953✔
1126
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
405,951✔
1127
        n," elements, but n should be nonnegative")))
1128
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
405,950✔
1129
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
405,962✔
1130
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
405,941✔
1131
    src′ = unalias(dest, src)
405,978✔
1132
    @inbounds for i = 0:n-1
811,870✔
1133
        dest[dstart+i] = src′[sstart+i]
20,432,301✔
1134
    end
40,458,667✔
1135
    return dest
405,935✔
1136
end
1137

1138
function copy(a::AbstractArray)
146,889✔
1139
    @_propagate_inbounds_meta
520✔
1140
    copymutable(a)
147,579✔
1141
end
1142

1143
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
6,039✔
1144
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1145
    if length(ir_dest) != length(ir_src)
6,039✔
1146
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1147
            length(ir_src)," and ",length(ir_dest),")")))
1148
    end
1149
    if length(jr_dest) != length(jr_src)
6,038✔
1150
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1151
            length(jr_src)," and ",length(jr_dest),")")))
1152
    end
1153
    @boundscheck checkbounds(B, ir_dest, jr_dest)
6,038✔
1154
    @boundscheck checkbounds(A, ir_src, jr_src)
6,038✔
1155
    A′ = unalias(B, A)
11,894✔
1156
    jdest = first(jr_dest)
6,038✔
1157
    for jsrc in jr_src
12,076✔
1158
        idest = first(ir_dest)
22,902✔
1159
        for isrc in ir_src
45,804✔
1160
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
200,034✔
1161
            idest += step(ir_dest)
199,595✔
1162
        end
376,288✔
1163
        jdest += step(jr_dest)
22,902✔
1164
    end
39,766✔
1165
    return B
6,038✔
1166
end
1167

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

1170
function copyto_axcheck!(dest, src)
27,773✔
1171
    _checkaxs(axes(dest), axes(src))
32,222✔
1172
    copyto!(dest, src)
47,727✔
1173
end
1174

1175
"""
1176
    copymutable(a)
1177

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

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

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

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

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

1206
# While the definitions for IndexLinear are all simple enough to inline on their
1207
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1208
# inlining.
1209
function iterate(A::AbstractArray, state=(eachindex(A),))
109,652,049✔
1210
    y = iterate(state...)
134,848,990✔
1211
    y === nothing && return nothing
111,524,203✔
1212
    A[y[1]], (state[1], tail(y)...)
111,102,862✔
1213
end
1214

1215
isempty(a::AbstractArray) = (length(a) == 0)
2,947,359,160✔
1216

1217

1218
## range conversions ##
1219

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

1227
## unsafe/pointer conversions ##
1228

1229
# note: the following type definitions don't mean any AbstractArray is convertible to
1230
# a data Ref. they just map the array element type to the pointer type for
1231
# convenience in cases that work.
1232
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
42,416,458✔
1233
function pointer(x::AbstractArray{T}, i::Integer) where T
8,457,087✔
1234
    @inline
5,079,130✔
1235
    unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
313,437,273✔
1236
end
1237

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

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

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

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

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

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

1276
julia> getindex(A, 2:4)
1277
3-element Vector{Int64}:
1278
 3
1279
 2
1280
 4
1281
```
1282
"""
1283
function getindex(A::AbstractArray, I...)
113,022,662✔
1284
    @_propagate_inbounds_meta
109,960,339✔
1285
    error_if_canonical_getindex(IndexStyle(A), A, I...)
109,960,339✔
1286
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
236,521,611✔
1287
end
1288
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1289
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
174,589,286✔
1290

1291
function unsafe_getindex(A::AbstractArray, I...)
262✔
1292
    @inline
262✔
1293
    @inbounds r = getindex(A, I...)
387✔
1294
    r
260✔
1295
end
1296

1297
struct CanonicalIndexError <: Exception
1298
    func::String
1299
    type::Any
1300
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
14✔
1301
end
1302

1303
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1304
    throw(CanonicalIndexError("getindex", typeof(A)))
1305
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1306
    throw(CanonicalIndexError("getindex", typeof(A)))
1307
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
109,958,961✔
1308

1309
## Internal definitions
1310
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1311
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1312

1313
## IndexLinear Scalar indexing: canonical method is one Int
1314
_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)
19,915,372✔
1315
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
×
1316
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
1,052,243✔
1317
    @inline
965,835✔
1318
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
36,977,314✔
1319
    @inbounds r = getindex(A, _to_linear_index(A, I...))
36,977,261✔
1320
    r
36,977,252✔
1321
end
1322
_to_linear_index(A::AbstractArray, i::Integer) = i
142,875✔
1323
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1,796,547✔
1324
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
289,002✔
1325
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
1,109,490✔
1326

1327
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1328
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
258,407✔
1329
    @inline
258,407✔
1330
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
258,420✔
1331
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
283,638✔
1332
    r
258,393✔
1333
end
1334
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
91,699,496✔
1335
    @_propagate_inbounds_meta
91,699,496✔
1336
    getindex(A, I...)
178,907,779✔
1337
end
1338
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
249,520✔
1339
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1340
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1341
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
5✔
1342
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1343
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
80,112✔
1344
    @inline
80,112✔
1345
    J, Jrem = IteratorsMD.split(I, Val(N))
80,112✔
1346
    _to_subscript_indices(A, J, Jrem)
80,112✔
1347
end
1348
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1349
    __to_subscript_indices(A, axes(A), J, Jrem)
1350
function __to_subscript_indices(A::AbstractArray,
2✔
1351
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1352
    @inline
2✔
1353
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1354
end
1355
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
80,110✔
1356
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
24,414✔
1357
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1358
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1359
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1360
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
249,520✔
1361

1362
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1363
# function that allows dispatch on array storage
1364

1365
"""
1366
    setindex!(A, X, inds...)
1367
    A[inds...] = X
1368

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

1372
# Examples
1373
```jldoctest
1374
julia> A = zeros(2,2);
1375

1376
julia> setindex!(A, [10, 20], [1, 2]);
1377

1378
julia> A[[3, 4]] = [30, 40];
1379

1380
julia> A
1381
2×2 Matrix{Float64}:
1382
 10.0  30.0
1383
 20.0  40.0
1384
```
1385
"""
1386
function setindex!(A::AbstractArray, v, I...)
2,854,908✔
1387
    @_propagate_inbounds_meta
2,742,625✔
1388
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,742,625✔
1389
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
3,918,012✔
1390
end
1391
function unsafe_setindex!(A::AbstractArray, v, I...)
732✔
1392
    @inline
732✔
1393
    @inbounds r = setindex!(A, v, I...)
732✔
1394
    r
730✔
1395
end
1396

1397
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
7✔
1398
    throw(CanonicalIndexError("setindex!", typeof(A)))
1399
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1400
    throw(CanonicalIndexError("setindex!", typeof(A)))
1401
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
2,742,484✔
1402

1403
## Internal definitions
1404
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1405
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1406

1407
## IndexLinear Scalar indexing
1408
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
419,675✔
1409
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
203,900✔
1410
    @inline
155,694✔
1411
    @boundscheck checkbounds(A, I...)
210,514✔
1412
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
210,477✔
1413
    r
210,476✔
1414
end
1415

1416
# IndexCartesian Scalar indexing
1417
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,323,567✔
1418
    @_propagate_inbounds_meta
2,323,567✔
1419
    setindex!(A, v, I...)
2,323,666✔
1420
end
1421
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
22,805✔
1422
    @inline
22,805✔
1423
    @boundscheck checkbounds(A, I...)
22,810✔
1424
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
30,512✔
1425
    r
22,800✔
1426
end
1427

1428
"""
1429
    parent(A)
1430

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

1436
# Examples
1437
```jldoctest
1438
julia> A = [1 2; 3 4]
1439
2×2 Matrix{Int64}:
1440
 1  2
1441
 3  4
1442

1443
julia> V = view(A, 1:2, :)
1444
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1445
 1  2
1446
 3  4
1447

1448
julia> parent(V)
1449
2×2 Matrix{Int64}:
1450
 1  2
1451
 3  4
1452
```
1453
"""
1454
function parent end
1455

1456
parent(a::AbstractArray) = a
2,116✔
1457

1458
## rudimentary aliasing detection ##
1459
"""
1460
    Base.unalias(dest, A)
1461

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

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

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

1472
See also [`Base.mightalias`](@ref).
1473
"""
1474
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
8,390,798✔
1475
unalias(dest, A::AbstractRange) = A
2,234,729✔
1476
unalias(dest, A) = A
2,565,983✔
1477

1478
"""
1479
    Base.unaliascopy(A)
1480

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

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

1501
"""
1502
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1503

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

1506
By default, this simply checks if either of the arrays reference the same memory
1507
regions, as identified by their [`Base.dataids`](@ref).
1508
"""
1509
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !_isdisjoint(dataids(A), dataids(B))
5,756,327✔
1510
mightalias(x, y) = false
×
1511

1512
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1513
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1514
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1515
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1516
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
5,645,052✔
1517
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
78,084✔
1518
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1519
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
2,076✔
1520
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
78,786✔
1521

1522
"""
1523
    Base.dataids(A::AbstractArray)
1524

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

1527
Custom arrays that would like to opt-in to aliasing detection of their component
1528
parts can specialize this method to return the concatenation of the `dataids` of
1529
their component parts.  A typical definition for an array that wraps a parent is
1530
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1531
"""
1532
dataids(A::AbstractArray) = (UInt(objectid(A)),)
147,080✔
1533
dataids(A::Array) = (UInt(pointer(A)),)
11,256,563✔
1534
dataids(::AbstractRange) = ()
6,729✔
1535
dataids(x) = ()
2,630✔
1536

1537
## get (getindex with a default value) ##
1538

1539
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1540
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1541

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

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

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

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

1576
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1577
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1578

1579
## structured matrix methods ##
1580
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
23,880✔
1581
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
5,591✔
1582

1583
## Concatenation ##
1584
eltypeof(x) = typeof(x)
20,997✔
1585
eltypeof(x::AbstractArray) = eltype(x)
13,949✔
1586

1587
promote_eltypeof() = error()
×
1588
promote_eltypeof(v1) = eltypeof(v1)
7,639✔
1589
promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
27,307✔
1590

1591
promote_eltype() = error()
×
1592
promote_eltype(v1) = eltype(v1)
3,086✔
1593
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
3,483✔
1594

1595
#TODO: ERROR CHECK
1596
_cat(catdim::Int) = Vector{Any}()
1✔
1597

1598
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1599
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1600

1601
## cat: special cases
1602
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
144✔
1603
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
292✔
1604
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
70✔
1605
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
497✔
1606

1607
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
1✔
1608
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
2✔
1609
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
10✔
1610
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
60✔
1611

1612
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
3✔
1613
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
4✔
1614

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

1620
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
791,844✔
1621
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
811,772✔
1622
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1623

1624
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
791,844✔
1625
    pos = 1
791,844✔
1626
    for k=1:Int(length(V))::Int
791,849✔
1627
        Vk = V[k]
792,368✔
1628
        p1 = pos + Int(length(Vk))::Int - 1
792,381✔
1629
        a[pos:p1] = Vk
5,701,350✔
1630
        pos = p1+1
792,368✔
1631
    end
792,892✔
1632
    a
791,844✔
1633
end
1634

1635
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
402✔
1636

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

1644

1645
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
174✔
1646
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
223✔
1647

1648
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
408✔
1649
    nargs = length(A)
408✔
1650
    nrows = size(A[1], 1)
409✔
1651
    ncols = 0
408✔
1652
    dense = true
408✔
1653
    for j = 1:nargs
414✔
1654
        Aj = A[j]
841✔
1655
        if size(Aj, 1) != nrows
1,080✔
1656
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1657
        end
1658
        dense &= isa(Aj,Array)
840✔
1659
        nd = ndims(Aj)
1,076✔
1660
        ncols += (nd==2 ? size(Aj,2) : 1)
1,024✔
1661
    end
1,273✔
1662
    B = similar(A[1], T, nrows, ncols)
407✔
1663
    pos = 1
407✔
1664
    if dense
407✔
1665
        for k=1:nargs
267✔
1666
            Ak = A[k]
555✔
1667
            n = length(Ak)
669✔
1668
            copyto!(B, pos, Ak, 1, n)
667✔
1669
            pos += n
555✔
1670
        end
845✔
1671
    else
1672
        for k=1:nargs
146✔
1673
            Ak = A[k]
284✔
1674
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
359✔
1675
            B[:, pos:p1] = Ak
284✔
1676
            pos = p1+1
284✔
1677
        end
284✔
1678
    end
1679
    return B
407✔
1680
end
1681

1682
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
51✔
1683
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
182✔
1684

1685
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
302✔
1686
    nargs = length(A)
302✔
1687
    nrows = sum(a->size(a, 1), A)::Int
1,017✔
1688
    ncols = size(A[1], 2)
302✔
1689
    for j = 2:nargs
303✔
1690
        if size(A[j], 2) != ncols
368✔
1691
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1692
        end
1693
    end
439✔
1694
    B = similar(A[1], T, nrows, ncols)
301✔
1695
    pos = 1
301✔
1696
    for k=1:nargs
302✔
1697
        Ak = A[k]
663✔
1698
        p1 = pos+size(Ak,1)::Int-1
765✔
1699
        B[pos:p1, :] = Ak
663✔
1700
        pos = p1+1
663✔
1701
    end
1,025✔
1702
    return B
301✔
1703
end
1704

1705
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
811,925✔
1706

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

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

1713
## cat: general case
1714

1715
# helper functions
1716
cat_size(A) = (1,)
21,564✔
1717
cat_size(A::AbstractArray) = size(A)
16,527✔
1718
cat_size(A, d) = 1
21,977✔
1719
cat_size(A::AbstractArray, d) = size(A, d)
24,283✔
1720

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

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

1727
cat_indices(A, d) = OneTo(1)
21,565✔
1728
cat_indices(A::AbstractArray, d) = axes(A, d)
17,686✔
1729

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

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

1752
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1753
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1754
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
427✔
1755
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
364✔
1756
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1757
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
2,910✔
1758
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1759
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
27✔
1760
    _cs(ndim, shape[1], 1)
29✔
1761
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
25✔
1762
end
1763
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
231✔
1764
    next = _cs(ndim, shape[1], nshape[1])
231✔
1765
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
231✔
1766
end
1767
@inline function _cshp(ndim::Int, dims, shape, nshape)
30,353✔
1768
    a = shape[1]
30,353✔
1769
    b = nshape[1]
30,353✔
1770
    next = dims[1] ? a + b : _cs(ndim, a, b)
31,120✔
1771
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
30,387✔
1772
end
1773

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

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

1785
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
7,503✔
1786

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

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

1803
function __cat_offset!(A, shape, catdims, offsets, x, X...)
38,080✔
1804
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1805
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
38,610✔
1806
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
38,083✔
1807
end
1808
__cat_offset!(A, shape, catdims, offsets) = A
8,810✔
1809

1810
function __cat_offset1!(A, shape, catdims, offsets, x)
38,076✔
1811
    inds = ntuple(length(offsets)) do i
38,236✔
1812
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
41,910✔
1813
    end
1814
    if x isa AbstractArray
38,076✔
1815
        A[inds...] = x
107,455✔
1816
    else
1817
        fill!(view(A, inds...), x)
22,004✔
1818
    end
1819
    newoffsets = ntuple(length(offsets)) do i
38,083✔
1820
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
43,538✔
1821
    end
1822
    return newoffsets
38,083✔
1823
end
1824

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1936
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
166✔
1937
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
167✔
1938

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

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

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

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

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

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

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

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

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

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

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

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

2005
# 2d horizontal and vertical concatenation
2006

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

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

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

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

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

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

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

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

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

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

2064
    nc = 0
679✔
2065
    for i=1:rows[1]
1,358✔
2066
        nc += size(as[i],2)
1,326✔
2067
    end
1,973✔
2068

2069
    nr = 0
679✔
2070
    a = 1
679✔
2071
    for i = 1:nbr
679✔
2072
        nr += size(as[a],1)
1,181✔
2073
        a += rows[i]
1,181✔
2074
    end
1,683✔
2075

2076
    out = similar(as[1], T, nr, nc)
679✔
2077

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

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

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

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

2128
function hvcat_fill!(a::Array, xs::Tuple)
466✔
2129
    nr, nc = size(a,1), size(a,2)
466✔
2130
    len = length(xs)
466✔
2131
    if nr*nc != len
466✔
2132
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2133
    end
2134
    k = 1
465✔
2135
    for i=1:nr
930✔
2136
        @inbounds for j=1:nc
2,502✔
2137
            a[i,j] = xs[k]
9,273✔
2138
            k += 1
8,596✔
2139
        end
15,941✔
2140
    end
2,037✔
2141
    a
465✔
2142
end
2143

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

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

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

2171
## N-dimensional concatenation ##
2172

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2268

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

2272
# 1-dimensional hvncat methods
2273

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

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

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

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

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

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

2315
    nd = N
17✔
2316

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

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

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

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

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

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

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

2374

2375
# balanced dimensions hvncat methods
2376

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

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

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

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

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

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

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

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

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

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

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

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

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

2524

2525
# unbalanced dimensions hvncat methods
2526

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

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

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

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

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

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

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

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

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

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

2603
    if row_first
15✔
2604
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2605
    end
2606

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

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

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

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

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

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

2666
"""
2667
    stack(iter; [dims])
2668

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

2672
By default the axes of the elements are placed first,
2673
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2674
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2675

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

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

2685
!!! compat "Julia 1.9"
2686
    This function requires at least Julia 1.9.
2687

2688
# Examples
2689
```jldoctest
2690
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2691

2692
julia> mat = stack(vecs)
2693
2×3 Matrix{Float32}:
2694
 1.0  30.0  500.0
2695
 2.0  40.0  600.0
2696

2697
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2698
true
2699

2700
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2701
true
2702

2703
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2704
2×4 Matrix{Int64}:
2705
  1   2   3   4
2706
 10  11  12  13
2707

2708
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2709
true
2710

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

2717
julia> x = rand(3,4);
2718

2719
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2720
true
2721
```
2722

2723
Higher-dimensional examples:
2724

2725
```jldoctest
2726
julia> A = rand(5, 7, 11);
2727

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

2730
julia> (element = size(first(E)), container = size(E))
2731
(element = (5, 11), container = (7,))
2732

2733
julia> stack(E) |> size
2734
(5, 11, 7)
2735

2736
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2737
true
2738

2739
julia> A == stack(E; dims=2)
2740
true
2741

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

2744
julia> (element = size(first(M)), container = size(M))
2745
(element = (2, 3), container = (5, 7))
2746

2747
julia> stack(M) |> size  # keeps all dimensions
2748
(2, 3, 5, 7)
2749

2750
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2751
(35, 2, 3)
2752

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

2759
"""
2760
    stack(f, args...; [dims])
2761

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

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

2769
See also [`mapslices`](@ref), [`eachcol`](@ref).
2770

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

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

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

2791
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2792

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

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

2824
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2825
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2826
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2827

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

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

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

2853
    newaxis = _vec_axis(A)
21✔
2854
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
141✔
2855
    B = similar(_ensure_array(x1), T, outax...)
23✔
2856

2857
    if dims == 1
21✔
2858
        _dim_stack!(Val(1), B, x1, xrest)
13✔
2859
    elseif dims == 2
8✔
2860
        _dim_stack!(Val(2), B, x1, xrest)
4✔
2861
    else
2862
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
2863
    end
2864
    B
18✔
2865
end
2866

2867
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
2868
    before = ntuple(d -> Colon(), dims - 1)
33✔
2869
    after = ntuple(d -> Colon(), ndims(B) - dims)
49✔
2870

2871
    i = firstindex(B, dims)
21✔
2872
    copyto!(view(B, before..., i, after...), x1)
40✔
2873

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

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

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

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

2895

2896
## Reductions and accumulates ##
2897

2898
function isequal(A::AbstractArray, B::AbstractArray)
246,856✔
2899
    if A === B return true end
247,111✔
2900
    if axes(A) != axes(B)
489,742✔
2901
        return false
3,442✔
2902
    end
2903
    for (a, b) in zip(A, B)
485,759✔
2904
        if !isequal(a, b)
91,227,218✔
2905
            return false
566✔
2906
        end
2907
    end
182,007,342✔
2908
    return true
242,593✔
2909
end
2910

2911
function cmp(A::AbstractVector, B::AbstractVector)
311✔
2912
    for (a, b) in zip(A, B)
622✔
2913
        if !isequal(a, b)
766✔
2914
            return isless(a, b) ? -1 : 1
296✔
2915
        end
2916
    end
925✔
2917
    return cmp(length(A), length(B))
15✔
2918
end
2919

2920
"""
2921
    isless(A::AbstractVector, B::AbstractVector)
2922

2923
Return `true` when `A` is less than `B` in lexicographic order.
2924
"""
2925
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
302✔
2926

2927
function (==)(A::AbstractArray, B::AbstractArray)
6,565,971✔
2928
    if axes(A) != axes(B)
13,128,758✔
2929
        return false
3,571✔
2930
    end
2931
    anymissing = false
6,551,450✔
2932
    for (a, b) in zip(A, B)
12,238,663✔
2933
        eq = (a == b)
335,905,165✔
2934
        if ismissing(eq)
301,379,141✔
2935
            anymissing = true
24✔
2936
        elseif !eq
335,017,228✔
2937
            return false
2,632✔
2938
        end
2939
    end
664,355,792✔
2940
    return anymissing ? missing : true
6,560,001✔
2941
end
2942

2943
# _sub2ind and _ind2sub
2944
# fallbacks
2945
function _sub2ind(A::AbstractArray, I...)
728,239✔
2946
    @inline
728,239✔
2947
    _sub2ind(axes(A), I...)
1,109,490✔
2948
end
2949

2950
function _ind2sub(A::AbstractArray, ind)
249,521✔
2951
    @inline
249,521✔
2952
    _ind2sub(axes(A), ind)
249,521✔
2953
end
2954

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

2961
# Generic cases
2962
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
2,146,916,774✔
2963
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
1,227,646✔
2964
# In 1d, there's a question of whether we're doing cartesian indexing
2965
# or linear indexing. Support only the former.
2966
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
2967
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2968
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
2969
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
2970

2971
_sub2ind_recurse(::Any, L, ind) = ind
1,259,992✔
2972
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,790✔
2973
    @inline
867✔
2974
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
12,143✔
2975
end
2976
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
2,518,172✔
2977
    @inline
1,995,558✔
2978
    r1 = inds[1]
2,029,190✔
2979
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
2,150,025,994✔
2980
end
2981

2982
nextL(L, l::Integer) = L*l
1,413,623✔
2983
nextL(L, r::AbstractUnitRange) = L*length(r)
1,694,597✔
2984
nextL(L, r::Slice) = L*length(r.indices)
×
2985
offsetin(i, l::Integer) = i-1
2,147,050,466✔
2986
offsetin(i, r::AbstractUnitRange) = i-first(r)
2,841,395✔
2987

2988
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
2989
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
2,063✔
2990
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
249,533✔
2991
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
2992
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2993
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
12✔
2994

2995
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
2996
function _ind2sub_recurse(indslast::NTuple{1}, ind)
251,596✔
2997
    @inline
251,596✔
2998
    (_lookup(ind, indslast[1]),)
251,596✔
2999
end
3000
function _ind2sub_recurse(inds, ind)
413,723✔
3001
    @inline
413,723✔
3002
    r1 = inds[1]
413,723✔
3003
    indnext, f, l = _div(ind, r1)
413,723✔
3004
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
413,723✔
3005
end
3006

3007
_lookup(ind, d::Integer) = ind+1
2,063✔
3008
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
249,533✔
3009
_div(ind, d::Integer) = div(ind, d), 1, d
2,063✔
3010
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
823,320✔
3011

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

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

3040
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3041
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3042
_sub2ind_vec(i) = ()
×
3043

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

3056
## iteration utilities ##
3057

3058
"""
3059
    foreach(f, c...) -> Nothing
3060

3061
Call function `f` on each element of iterable `c`.
3062
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3063
any iterator is finished.
3064

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

3068
# Examples
3069
```jldoctest
3070
julia> tri = 1:3:7; res = Int[];
3071

3072
julia> foreach(x -> push!(res, x^2), tri)
3073

3074
julia> res
3075
3-element Vector{$(Int)}:
3076
  1
3077
 16
3078
 49
3079

3080
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3081
1 with a
3082
4 with b
3083
7 with c
3084
```
3085
"""
3086
foreach(f) = (f(); nothing)
2✔
3087
foreach(f, itr) = (for x in itr; f(x); end; nothing)
213,197,075✔
3088
foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
11✔
3089

3090
## map over arrays ##
3091

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

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

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

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

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

3115
[:, :, 2] =
3116
 11  13  15  17  19
3117
 12  14  16  18  20
3118

3119
[:, :, 3] =
3120
 21  23  25  27  29
3121
 22  24  26  28  30
3122

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

3125
julia> B = mapslices(f, A, dims=(1,2))
3126
1×4×3 Array{$Int, 3}:
3127
[:, :, 1] =
3128
 1  1  1  1
3129

3130
[:, :, 2] =
3131
 11  11  11  11
3132

3133
[:, :, 3] =
3134
 21  21  21  21
3135

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

3138
julia> B == stack(f2, eachslice(A, dims=3))
3139
true
3140

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

3143
julia> mapslices(g, A, dims=[1,3])
3144
1×5×1 Array{Rational{$Int}, 3}:
3145
[:, :, 1] =
3146
 1//21  3//23  1//5  7//27  9//29
3147

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

3156
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3157
true
3158
```
3159

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

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

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

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

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

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

3215
    # That skips the first element, which we already have:
3216
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
2,561✔
3217
    concatenate_setindex!(R, res1, ridx...)
455✔
3218

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

3226
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
458✔
3227
    return R
442✔
3228
end
3229

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

3257
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
3,702✔
3258
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
448✔
3259

3260
## 0 arguments
3261

3262
map(f) = f()
1✔
3263

3264
## 1 argument
3265

3266
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,140✔
3267
    for (i,j) in zip(eachindex(dest),eachindex(A))
240,661,010✔
3268
        val = f(@inbounds A[j])
243,243,777✔
3269
        @inbounds dest[i] = val
145,150,897✔
3270
    end
179,900,135✔
3271
    return dest
130,461,561✔
3272
end
3273

3274
# map on collections
3275
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
90,851✔
3276

3277
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
2,492✔
3278
mapany(f, itr) = Any[f(x) for x in itr]
×
3279

3280
"""
3281
    map(f, c...) -> collection
3282

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

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

3288
# Examples
3289
```jldoctest
3290
julia> map(x -> x * 2, [1, 2, 3])
3291
3-element Vector{Int64}:
3292
 2
3293
 4
3294
 6
3295

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

3305
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3306
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3307

3308
## 2 argument
3309
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
346✔
3310
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
679✔
3311
        @inbounds a, b = A[j], B[k]
386,785✔
3312
        val = f(a, b)
338,102✔
3313
        @inbounds dest[i] = val
338,102✔
3314
    end
675,871✔
3315
    return dest
346✔
3316
end
3317

3318
## N argument
3319

3320
@inline ith_all(i, ::Tuple{}) = ()
4,030✔
3321
function ith_all(i, as)
12,090✔
3322
    @_propagate_inbounds_meta
12,090✔
3323
    return (as[1][i], ith_all(i, tail(as))...)
18,930✔
3324
end
3325

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

3337
"""
3338
    map!(function, destination, collection...)
3339

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

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

3345
# Examples
3346
```jldoctest
3347
julia> a = zeros(3);
3348

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

3351
julia> a
3352
3-element Vector{Float64}:
3353
 2.0
3354
 4.0
3355
 6.0
3356

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

3372
"""
3373
    map(f, A::AbstractArray...) -> N-array
3374

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

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

3380
# Examples
3381
```
3382
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3383
2×2 Matrix{Rational{$Int}}:
3384
 1//4  2//3
3385
 3//2  4//1
3386

3387
julia> map(+, [1 2; 3 4], zeros(2,1))
3388
ERROR: DimensionMismatch
3389

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

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

3406
## hashing AbstractArray ##
3407

3408
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3409
function hash(A::AbstractArray, h::UInt)
12,450✔
3410
    h += hash_abstractarray_seed
12,450✔
3411
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3412
    # Instead hash the tuple of firsts and lasts along each dimension
3413
    h = hash(map(first, axes(A)), h)
12,687✔
3414
    h = hash(map(last, axes(A)), h)
12,687✔
3415

3416
    # For short arrays, it's not worth doing anything complicated
3417
    if length(A) < 8192
12,687✔
3418
        for x in A
17,204✔
3419
            h = hash(x, h)
248,740✔
3420
        end
386,140✔
3421
        return h
12,446✔
3422
    end
3423

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

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

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

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

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

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

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

3478
    return h
4✔
3479
end
3480

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

3489

3490
## keepat! ##
3491

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

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

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

3526
## 1-d circshift ##
3527
function circshift!(a::AbstractVector, shift::Integer)
1,137✔
3528
    n = length(a)
1,137✔
3529
    n == 0 && return
1,137✔
3530
    shift = mod(shift, n)
2,274✔
3531
    shift == 0 && return
1,137✔
3532
    l = lastindex(a)
625✔
3533
    reverse!(a, firstindex(a), l-shift)
625✔
3534
    reverse!(a, l-shift+1, lastindex(a))
625✔
3535
    reverse!(a)
625✔
3536
    return a
625✔
3537
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