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

JuliaLang / julia / #37773

08 May 2024 07:57AM UTC coverage: 86.275% (-0.5%) from 86.821%
#37773

push

local

web-flow
Stabilize `MulAddMul` strategically (#52439)

Co-authored-by: Ashley Milsted <ashmilsted@gmail.com>

58 of 79 new or added lines in 4 files covered. (73.42%)

1130 existing lines in 37 files now uncovered.

74527 of 86383 relevant lines covered (86.28%)

15994665.82 hits per line

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

91.24
/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
59,334✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
5,757✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
8,303✔
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
4,235,739✔
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}
272✔
76
    @inline
72,333,092✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
72,361,051✔
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)
1,196✔
97
    @inline
734,966,890✔
98
    map(unchecked_oneto, size(A))
2,147,483,647✔
99
end
100

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

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

108
See also [`require_one_based_indexing`](@ref).
109
"""
110
has_offset_axes() = false
×
111
has_offset_axes(A) = _any_tuple(x->Int(first(x))::Int != 1, false, axes(A)...)
811,788✔
112
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
426,317✔
113
has_offset_axes(::Colon) = false
×
114
has_offset_axes(::Array) = false
×
115
# note: this could call `any` directly if the compiler can infer it. We don't use _any_tuple
116
# here because it stops full elision in some cases (#49332) and we don't need handling of
117
# `missing` (has_offset_axes(A) always returns a Bool)
118
has_offset_axes(A, As...) = has_offset_axes(A) || has_offset_axes(As...)
9,497,833✔
119

120

121
"""
122
    require_one_based_indexing(A::AbstractArray)
123
    require_one_based_indexing(A,B...)
124

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

128
!!! compat "Julia 1.2"
129
     This function requires at least Julia 1.2.
130
"""
131
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"))
5,719,277✔
132

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

140
"""
141
    keys(a::AbstractArray)
142

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

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

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

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

161
julia> keys([4 5; 6 7])
162
CartesianIndices((2, 2))
163
```
164
"""
165
keys(a::AbstractArray) = CartesianIndices(axes(a))
29,073✔
166
keys(a::AbstractVector) = LinearIndices(a)
80,118,246✔
167

168
"""
169
    keytype(T::Type{<:AbstractArray})
170
    keytype(A::AbstractArray)
171

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

176
# Examples
177
```jldoctest
178
julia> keytype([1, 2, 3]) == Int
179
true
180

181
julia> keytype([1 2; 3 4])
182
CartesianIndex{2}
183
```
184

185
!!! compat "Julia 1.2"
186
     For arrays, this function requires at least Julia 1.2.
187
"""
188
keytype(a::AbstractArray) = keytype(typeof(a))
45,016,929✔
189
keytype(::Type{Union{}}, slurp...) = eltype(Union{})
×
190

191
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
2✔
192
keytype(A::Type{<:AbstractVector}) = Int
×
193

194
valtype(a::AbstractArray) = valtype(typeof(a))
15✔
195
valtype(::Type{Union{}}, slurp...) = eltype(Union{})
×
196

197
"""
198
    valtype(T::Type{<:AbstractArray})
199
    valtype(A::AbstractArray)
200

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

204
# Examples
205
```jldoctest
206
julia> valtype(["one", "two", "three"])
207
String
208
```
209

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

215
prevind(::AbstractArray, i::Integer) = Int(i)-1
265,909✔
216
nextind(::AbstractArray, i::Integer) = Int(i)+1
308,759,020✔
217

218

219
"""
220
    eltype(type)
221

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

228
See also: [`keytype`](@ref), [`typeof`](@ref).
229

230
# Examples
231
```jldoctest
232
julia> eltype(fill(1f0, (2,2)))
233
Float32
234

235
julia> eltype(fill(0x1, (2,2)))
236
UInt8
237
```
238
"""
239
eltype(::Type) = Any
×
240
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
1✔
241
eltype(x) = eltype(typeof(x))
17,135,225✔
242
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
15,905,526✔
243

244
"""
245
    elsize(type)
246

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

251
# Examples
252
```jldoctest
253
julia> Base.elsize(rand(Float32, 10))
254
4
255
```
256
"""
257
elsize(A::AbstractArray) = elsize(typeof(A))
78,768,389✔
258

259
"""
260
    ndims(A::AbstractArray) -> Integer
261

262
Return the number of dimensions of `A`.
263

264
See also: [`size`](@ref), [`axes`](@ref).
265

266
# Examples
267
```jldoctest
268
julia> A = fill(1, (3,4,5));
269

270
julia> ndims(A)
271
3
272
```
273
"""
274
ndims(::AbstractArray{T,N}) where {T,N} = N::Int
38,353,289✔
275
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N::Int
59✔
276
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
×
277

278
"""
279
    length(collection) -> Integer
280

281
Return the number of elements in the collection.
282

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

285
See also: [`size`](@ref), [`ndims`](@ref), [`eachindex`](@ref).
286

287
# Examples
288
```jldoctest
289
julia> length(1:5)
290
5
291

292
julia> length([1, 2, 3, 4])
293
4
294

295
julia> length([1 2; 3 4])
296
4
297
```
298
"""
299
length
300

301
"""
302
    length(A::AbstractArray)
303

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

306
# Examples
307
```jldoctest
308
julia> length([1, 2, 3, 4])
309
4
310

311
julia> length([1 2; 3 4])
312
4
313
```
314
"""
315
length(t::AbstractArray) = (@inline; prod(size(t)))
21,503,754✔
316

317
# `eachindex` is mostly an optimization of `keys`
318
eachindex(itrs...) = keys(itrs...)
263✔
319

320
# eachindex iterates over all indices. IndexCartesian definitions are later.
321
eachindex(A::AbstractVector) = (@inline(); axes1(A))
1,237,596,258✔
322

323

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

331
"""
332
    eachindex(A...)
333
    eachindex(::IndexStyle, A::AbstractArray...)
334

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

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

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

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

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

359
# Examples
360
```jldoctest
361
julia> A = [10 20; 30 40];
362

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

371
julia> for i in eachindex(view(A, 1:2, 1:1)) # Cartesian indexing
372
           println(i)
373
       end
374
CartesianIndex(1, 1)
375
CartesianIndex(2, 1)
376
```
377
"""
378
eachindex(A::AbstractArray) = (@inline(); eachindex(IndexStyle(A), A))
341,090✔
379

380
function eachindex(A::AbstractArray, B::AbstractArray)
7✔
381
    @inline
38✔
382
    eachindex(IndexStyle(A,B), A, B)
38✔
383
end
384
function eachindex(A::AbstractArray, B::AbstractArray...)
2✔
385
    @inline
2✔
386
    eachindex(IndexStyle(A,B...), A, B...)
2✔
387
end
388
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
23,732,110✔
389
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
2,147,483,647✔
390
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
1✔
391
    @inline
35✔
392
    indsA = eachindex(IndexLinear(), A)
35✔
393
    _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
72✔
394
        throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
395
    indsA
34✔
396
end
397
function _all_match_first(f::F, inds, A, B...) where F<:Function
398
    @inline
44✔
399
    (inds == f(A)) & _all_match_first(f, inds, B...)
51✔
400
end
401
_all_match_first(f::F, inds) where F<:Function = true
×
402

403
# keys with an IndexStyle
404
keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...)
×
405

406
"""
407
    lastindex(collection) -> Integer
408
    lastindex(collection, d) -> Integer
409

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

412
The syntaxes `A[end]` and `A[end, end]` lower to `A[lastindex(A)]` and
413
`A[lastindex(A, 1), lastindex(A, 2)]`, respectively.
414

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

417
# Examples
418
```jldoctest
419
julia> lastindex([1,2,4])
420
3
421

422
julia> lastindex(rand(3,4,5), 2)
423
4
424
```
425
"""
426
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
2,147,483,647✔
427
lastindex(a, d) = (@inline; last(axes(a, d)))
6,820✔
428

429
"""
430
    firstindex(collection) -> Integer
431
    firstindex(collection, d) -> Integer
432

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

435
The syntaxes `A[begin]` and `A[1, begin]` lower to `A[firstindex(A)]` and
436
`A[1, firstindex(A, 2)]`, respectively.
437

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

440
# Examples
441
```jldoctest
442
julia> firstindex([1,2,4])
443
1
444

445
julia> firstindex(rand(3,4,5), 2)
446
1
447
```
448
"""
449
firstindex(a::AbstractArray) = (@inline; first(eachindex(IndexLinear(), a)))
54,864,936✔
450
firstindex(a, d) = (@inline; first(axes(a, d)))
2,939✔
451

452
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
406,549✔
453

454
"""
455
    first(coll)
456

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

460
See also: [`only`](@ref), [`firstindex`](@ref), [`last`](@ref).
461

462
# Examples
463
```jldoctest
464
julia> first(2:2:10)
465
2
466

467
julia> first([1; 2; 3; 4])
468
1
469
```
470
"""
471
function first(itr)
1,032✔
472
    x = iterate(itr)
2,052✔
473
    x === nothing && throw(ArgumentError("collection must be non-empty"))
1,076✔
474
    x[1]
1,074✔
475
end
476

477
"""
478
    first(itr, n::Integer)
479

480
Get the first `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
481
long enough.
482

483
See also: [`startswith`](@ref), [`Iterators.take`](@ref).
484

485
!!! compat "Julia 1.6"
486
    This method requires at least Julia 1.6.
487

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

495
julia> first(1:6, 10)
496
1:6
497

498
julia> first(Bool[], 1)
499
Bool[]
500
```
501
"""
502
first(itr, n::Integer) = collect(Iterators.take(itr, n))
10✔
503
# Faster method for vectors
504
function first(v::AbstractVector, n::Integer)
1,467✔
505
    n < 0 && throw(ArgumentError("Number of elements must be non-negative"))
1,478✔
506
    v[range(begin, length=min(n, checked_length(v)))]
1,484✔
507
end
508

509
"""
510
    last(coll)
511

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

516
See also [`first`](@ref), [`endswith`](@ref).
517

518
# Examples
519
```jldoctest
520
julia> last(1:2:10)
521
9
522

523
julia> last([1; 2; 3; 4])
524
4
525
```
526
"""
527
last(a) = a[end]
365,929,915✔
528

529
"""
530
    last(itr, n::Integer)
531

532
Get the last `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
533
long enough.
534

535
!!! compat "Julia 1.6"
536
    This method requires at least Julia 1.6.
537

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

545
julia> last(1:6, 10)
546
1:6
547

548
julia> last(Float64[], 1)
549
Float64[]
550
```
551
"""
552
last(itr, n::Integer) = reverse!(collect(Iterators.take(Iterators.reverse(itr), n)))
60✔
553
# Faster method for arrays
554
function last(v::AbstractVector, n::Integer)
1,828✔
555
    n < 0 && throw(ArgumentError("Number of elements must be non-negative"))
1,873✔
556
    v[range(stop=lastindex(v), length=min(n, checked_length(v)))]
1,913✔
557
end
558

559
"""
560
    strides(A)
561

562
Return a tuple of the memory strides in each dimension.
563

564
See also: [`stride`](@ref).
565

566
# Examples
567
```jldoctest
568
julia> A = fill(1, (3,4,5));
569

570
julia> strides(A)
571
(1, 3, 12)
572
```
573
"""
574
function strides end
575

576
"""
577
    stride(A, k::Integer)
578

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

581
See also: [`strides`](@ref).
582

583
# Examples
584
```jldoctest
585
julia> A = fill(1, (3,4,5));
586

587
julia> stride(A,2)
588
3
589

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

606
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
36,490,802✔
607
size_to_strides(s, d) = (s,)
36,420,473✔
608
size_to_strides(s) = ()
1✔
609

610
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
4✔
611
    @boundscheck checkbounds(A, I...)
37✔
612
    return true
31✔
613
end
614

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

636
## Bounds checking ##
637

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

652
"""
653
    checkbounds(Bool, A, I...)
654

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

660
See also [`checkindex`](@ref).
661

662
# Examples
663
```jldoctest
664
julia> A = rand(3, 3);
665

666
julia> checkbounds(Bool, A, 2)
667
true
668

669
julia> checkbounds(Bool, A, 3, 4)
670
false
671

672
julia> checkbounds(Bool, A, 1:3)
673
true
674

675
julia> checkbounds(Bool, A, 1:3, 2:4)
676
false
677
```
678
"""
679
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
3,934✔
680
    @inline
458,447,351✔
681
    checkbounds_indices(Bool, axes(A), I)
474,026,994✔
682
end
683

684
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index;
685
# indices that do not allow linear indexing (e.g., logical arrays, cartesian indices, etc)
686
# must add specialized methods to implement their restrictions
687
function checkbounds(::Type{Bool}, A::AbstractArray, i)
76✔
688
    @inline
914,436,903✔
689
    return checkindex(Bool, eachindex(IndexLinear(), A), i)
2,147,483,647✔
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...)
4,029✔
698
    @inline
1,331,433,397✔
699
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
2,147,483,647✔
700
    nothing
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}, inds::Tuple, I::Tuple{Any, Vararg})
4,740✔
724
    @inline
33,379,131✔
725
    return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
1,094,818,975✔
726
        checkbounds_indices(Bool, safe_tail(inds), tail(I))
727
end
728

729
checkbounds_indices(::Type{Bool}, inds::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, inds))
577,988✔
730

731
# check along a single dimension
732
"""
733
    checkindex(Bool, inds::AbstractUnitRange, index)
734

735
Return `true` if the given `index` is within the bounds of
736
`inds`. Custom types that would like to behave as indices for all
737
arrays can extend this method in order to provide a specialized bounds
738
checking implementation.
739

740
See also [`checkbounds`](@ref).
741

742
# Examples
743
```jldoctest
744
julia> checkindex(Bool, 1:20, 8)
745
true
746

747
julia> checkindex(Bool, 1:20, 21)
748
false
749
```
750
"""
751
checkindex(::Type{Bool}, inds, i) = throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
2✔
752
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
32,100,483✔
753
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
9,613,311✔
754
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
2,147,483,647✔
755
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
×
756
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
×
757
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::AbstractRange) =
343,028,008✔
758
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
759
# range like indices with cheap `extrema`
760
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::LinearIndices) =
145✔
761
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
762

763
function checkindex(::Type{Bool}, inds, I::AbstractArray)
764
    @inline
7,050✔
765
    b = true
7,050✔
766
    for i in I
21,498✔
767
        b &= checkindex(Bool, inds, i)
6,553,732✔
768
    end
6,561,695✔
769
    b
19,170✔
770
end
771

772
# See also specializations in multidimensional
773

774
## Constructors ##
775

776
# default arguments to similar()
777
"""
778
    similar(array, [element_type=eltype(array)], [dims=size(array)])
779

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

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

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

792
```julia-repl
793
julia> similar(1:10, 1, 4)
794
1×4 Matrix{Int64}:
795
 4419743872  4374413872  4419743888  0
796
```
797

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

801
```julia-repl
802
julia> similar(trues(10,10), 2)
803
2-element BitVector:
804
 0
805
 0
806
```
807

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

811
```julia-repl
812
julia> similar(falses(10), Float64, 2, 4)
813
2×4 Matrix{Float64}:
814
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
815
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
816
```
817

818
See also: [`undef`](@ref), [`isassigned`](@ref).
819
"""
820
similar(a::AbstractArray{T}) where {T}                             = similar(a, T)
12,416✔
821
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
8,367✔
822
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
82,156,850✔
823
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
3,490✔
824
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
16,443,172✔
825
# Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
826
# thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
827
# but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
828
# define this method to convert supported axes to Ints, with the expectation that an offset array
829
# package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
830
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
233,808✔
831
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims))
5✔
832
# similar creates an Array by default
833
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N}    = Array{T,N}(undef, dims)
16,385,190✔
834

835
to_shape(::Tuple{}) = ()
37✔
836
to_shape(dims::Dims) = dims
6,954✔
837
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
4,254,921✔
838
# each dimension
839
to_shape(i::Int) = i
111✔
840
to_shape(i::Integer) = Int(i)
173✔
841
to_shape(r::OneTo) = Int(last(r))
23,547✔
842
to_shape(r::AbstractUnitRange) = r
289✔
843

844
"""
845
    similar(storagetype, axes)
846

847
Create an uninitialized mutable array analogous to that specified by
848
`storagetype`, but with `axes` specified by the last
849
argument.
850

851
**Examples**:
852

853
    similar(Array{Int}, axes(A))
854

855
creates an array that "acts like" an `Array{Int}` (and might indeed be
856
backed by one), but which is indexed identically to `A`. If `A` has
857
conventional indexing, this will be identical to
858
`Array{Int}(undef, size(A))`, but if `A` has unconventional indexing then the
859
indices of the result will match `A`.
860

861
    similar(BitArray, (axes(A, 2),))
862

863
would create a 1-dimensional logical array whose indices match those
864
of the columns of `A`.
865
"""
866
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
93✔
867
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
1,049,417,548✔
868
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
1,049,418,094✔
869

870
"""
871
    empty(v::AbstractVector, [eltype])
872

873
Create an empty vector similar to `v`, optionally changing the `eltype`.
874

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

877
# Examples
878

879
```jldoctest
880
julia> empty([1.0, 2.0, 3.0])
881
Float64[]
882

883
julia> empty([1.0, 2.0, 3.0], String)
884
String[]
885
```
886
"""
887
empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = similar(a, U, 0)
516✔
888

889
# like empty, but should return a mutable collection, a Vector by default
890
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
239✔
891
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
65✔
892

893
"""
894
    copy!(dst, src) -> dst
895

896
In-place [`copy`](@ref) of `src` into `dst`, discarding any pre-existing
897
elements in `dst`.
898
If `dst` and `src` are of the same type, `dst == src` should hold after
899
the call. If `dst` and `src` are vector types, they must have equal
900
offset. If `dst` and `src` are multidimensional arrays, they must have
901
equal [`axes`](@ref).
902

903
$(_DOCS_ALIASING_WARNING)
904

905
See also [`copyto!`](@ref).
906

907
!!! note
908
    When operating on vector types, if `dst` and `src` are not of the
909
    same length, `dst` is resized to `length(src)` prior to the `copy`.
910

911
!!! compat "Julia 1.1"
912
    This method requires at least Julia 1.1. In Julia 1.0 this method
913
    is available from the `Future` standard library as `Future.copy!`.
914
"""
915
function copy!(dst::AbstractVector, src::AbstractVector)
21,489,576✔
916
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
96✔
917
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
918
    if length(dst) != length(src)
21,489,668✔
919
        resize!(dst, length(src))
21,268,917✔
920
    end
921
    copyto!(dst, src)
21,489,760✔
922
end
923

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

930
## from general iterable to any array
931

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

936
function copyto!(dest::AbstractArray, src)
11,697,089✔
937
    destiter = eachindex(dest)
11,710,806✔
938
    y = iterate(destiter)
11,710,816✔
939
    for x in src
15,599,402✔
940
        y === nothing &&
5,718,913✔
941
            throw(ArgumentError("destination has fewer elements than required"))
942
        dest[y[1]] = x
5,718,912✔
943
        y = iterate(destiter, y[2])
9,429,940✔
944
    end
9,399,502✔
945
    return dest
11,710,804✔
946
end
947

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

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

994
# this method must be separate from the above since src might not have a length
995
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
1,320,474✔
996
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
1,320,474✔
997
        ", elements, but n should be non-negative")))
998
    n == 0 && return dest
1,320,473✔
999
    dmax = dstart + n - 1
1,320,468✔
1000
    inds = LinearIndices(dest)
1,320,468✔
1001
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
2,640,934✔
1002
        sstart < 1 && throw(ArgumentError(LazyString("source start offset (",
4✔
1003
            sstart,") is < 1")))
1004
        throw(BoundsError(dest, dstart:dmax))
3✔
1005
    end
1006
    y = iterate(src)
1,320,464✔
1007
    for j = 1:(sstart-1)
1,373,887✔
1008
        if y === nothing
2,147,483,647✔
1009
            throw(ArgumentError(LazyString(
1✔
1010
                "source has fewer elements than required, ",
1011
                "expected at least ",sstart,", got ",j-1)))
1012
        end
1013
        y = iterate(src, y[2])
2,147,483,647✔
1014
    end
2,147,483,647✔
1015
    i = Int(dstart)
1,320,463✔
1016
    while i <= dmax && y !== nothing
13,245,206✔
1017
        val, st = y
10,492,303✔
1018
        @inbounds dest[i] = val
11,924,743✔
1019
        y = iterate(src, st)
13,144,908✔
1020
        i += 1
11,924,743✔
1021
    end
11,924,743✔
1022
    i <= dmax && throw(BoundsError(dest, i))
1,320,463✔
1023
    return dest
1,320,462✔
1024
end
1025

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

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

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

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

1038
$(_DOCS_ALIASING_WARNING)
1039

1040
# Examples
1041
```jldoctest
1042
julia> x = [1., 0., 3., 0., 5.];
1043

1044
julia> y = zeros(7);
1045

1046
julia> copyto!(y, x);
1047

1048
julia> y
1049
7-element Vector{Float64}:
1050
 1.0
1051
 0.0
1052
 3.0
1053
 0.0
1054
 5.0
1055
 0.0
1056
 0.0
1057
```
1058
"""
1059
function copyto!(dest::AbstractArray, src::AbstractArray)
2,643,838✔
1060
    isempty(src) && return dest
2,986,150✔
1061
    if dest isa BitArray
2,638,954✔
1062
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1063
        return _copyto_bitarray!(dest, src)
1✔
1064
    end
1065
    src′ = unalias(dest, src)
2,983,276✔
1066
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,985,653✔
1067
end
1068

UNCOV
1069
function copyto!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
×
UNCOV
1070
    isempty(src) && return dest
×
UNCOV
1071
    src′ = unalias(dest, src)
×
UNCOV
1072
    copyto_unaliased!(deststyle, dest, srcstyle, src′)
×
1073
end
1074

1075
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
352,005✔
1076
    isempty(src) && return dest
2,979,291✔
1077
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,979,292✔
1078
    idf, isf = first(destinds), first(srcinds)
2,632,594✔
1079
    Δi = idf - isf
2,632,594✔
1080
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,979,292✔
1081
        throw(BoundsError(dest, srcinds))
1082
    if deststyle isa IndexLinear
2,632,593✔
1083
        if srcstyle isa IndexLinear
2,628,366✔
1084
            # Single-index implementation
1085
            @inbounds for i in srcinds
2,672,086✔
1086
                if isassigned(src, i)
37,382,467✔
1087
                    dest[i + Δi] = src[i]
37,383,531✔
1088
                else
1089
                    _unsetindex!(dest, i + Δi)
43✔
1090
                end
1091
            end
72,092,850✔
1092
        else
1093
            # Dual-index implementation
1094
            i = idf - 1
120,541✔
1095
            @inbounds for a in eachindex(src)
334,634✔
1096
                i += 1
4,173,834✔
1097
                if isassigned(src, a)
4,176,272✔
1098
                    dest[i] = src[a]
4,173,826✔
1099
                else
1100
                    _unsetindex!(dest, i)
8✔
1101
                end
1102
            end
4,753,221✔
1103
        end
1104
    else
1105
        iterdest, itersrc = eachindex(dest), eachindex(src)
4,227✔
1106
        if iterdest == itersrc
4,228✔
1107
            # Shared-iterator implementation
1108
            @inbounds for I in iterdest
2,491✔
1109
                if isassigned(src, I)
6,089,130✔
1110
                    dest[I] = src[I]
6,089,011✔
1111
                else
1112
                    _unsetindex!(dest, I)
9✔
1113
                end
1114
            end
12,091,187✔
1115
        else
1116
            # Dual-iterator implementation
1117
            ret = iterate(iterdest)
5,934✔
1118
            @inbounds for a in itersrc
2,993✔
1119
                idx, state = ret::NTuple{2,Any}
2,033,818✔
1120
                if isassigned(src, a)
2,033,818✔
1121
                    dest[idx] = src[a]
2,033,814✔
1122
                else
1123
                    _unsetindex!(dest, idx)
4✔
1124
                end
1125
                ret = iterate(iterdest, state)
2,036,764✔
1126
            end
4,064,666✔
1127
        end
1128
    end
1129
    return dest
2,979,288✔
1130
end
1131

1132
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
72✔
1133
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
22,218✔
1134
end
1135

1136
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray, sstart::Integer)
22✔
1137
    srcinds = LinearIndices(src)
22✔
1138
    checkbounds(Bool, srcinds, sstart) || throw(BoundsError(src, sstart))
31✔
1139
    copyto!(dest, dstart, src, sstart, last(srcinds)-sstart+1)
13✔
1140
end
1141

1142
function copyto!(dest::AbstractArray, dstart::Integer,
865,330✔
1143
                 src::AbstractArray, sstart::Integer,
1144
                 n::Integer)
1145
    n == 0 && return dest
865,330✔
1146
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
865,298✔
1147
        n," elements, but n should be non-negative")))
1148
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
865,297✔
1149
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
865,309✔
1150
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
865,288✔
1151
    src′ = unalias(dest, src)
865,282✔
1152
    @inbounds for i = 0:n-1
865,359✔
1153
        if isassigned(src′, sstart+i)
58,046,042✔
1154
            dest[dstart+i] = src′[sstart+i]
58,046,038✔
1155
        else
UNCOV
1156
            _unsetindex!(dest, dstart+i)
×
1157
        end
1158
    end
115,226,794✔
1159
    return dest
865,282✔
1160
end
1161

1162
function copy(a::AbstractArray)
142,415✔
1163
    @_propagate_inbounds_meta
146,789✔
1164
    copymutable(a)
148,984✔
1165
end
1166

1167
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
3✔
1168
                 A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1169
    if length(ir_dest) != length(ir_src)
3✔
1170
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1171
            length(ir_src)," and ",length(ir_dest),")")))
1172
    end
1173
    if length(jr_dest) != length(jr_src)
2✔
UNCOV
1174
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1175
            length(jr_src)," and ",length(jr_dest),")")))
1176
    end
1177
    @boundscheck checkbounds(B, ir_dest, jr_dest)
2✔
1178
    @boundscheck checkbounds(A, ir_src, jr_src)
2✔
1179
    A′ = unalias(B, A)
2✔
1180
    jdest = first(jr_dest)
2✔
1181
    for jsrc in jr_src
3✔
1182
        idest = first(ir_dest)
4✔
1183
        for isrc in ir_src
5✔
1184
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
8✔
1185
            idest += step(ir_dest)
8✔
1186
        end
12✔
1187
        jdest += step(jr_dest)
4✔
1188
    end
6✔
1189
    return B
2✔
1190
end
1191

1192
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
241,318✔
1193

1194
function copyto_axcheck!(dest, src)
490✔
1195
    _checkaxs(axes(dest), axes(src))
220,474✔
1196
    copyto!(dest, src)
303,253✔
1197
end
1198

1199
"""
1200
    copymutable(a)
1201

1202
Make a mutable copy of an array or iterable `a`.  For `a::Array`,
1203
this is equivalent to `copy(a)`, but for other array types it may
1204
differ depending on the type of `similar(a)`.  For generic iterables
1205
this is equivalent to `collect(a)`.
1206

1207
# Examples
1208
```jldoctest
1209
julia> tup = (1, 2, 3)
1210
(1, 2, 3)
1211

1212
julia> Base.copymutable(tup)
1213
3-element Vector{Int64}:
1214
 1
1215
 2
1216
 3
1217
```
1218
"""
1219
function copymutable(a::AbstractArray)
44✔
1220
    @_propagate_inbounds_meta
149,453✔
1221
    copyto!(similar(a), a)
163,503✔
1222
end
1223
copymutable(itr) = collect(itr)
1✔
1224

1225
zero(x::AbstractArray{T}) where {T<:Number} = fill!(similar(x, typeof(zero(T))), zero(T))
4,429✔
1226
zero(x::AbstractArray{S}) where {S<:Union{Missing, Number}} = fill!(similar(x, typeof(zero(S))), zero(S))
3✔
1227
zero(x::AbstractArray) = map(zero, x)
11✔
1228

1229
function _one(unit::T, mat::AbstractMatrix) where {T}
164✔
1230
    (rows, cols) = axes(mat)
164✔
1231
    (length(rows) == length(cols)) ||
164✔
1232
      throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
1233
    zer = zero(unit)::T
164✔
1234
    require_one_based_indexing(mat)
164✔
1235
    I = similar(mat, T)
328✔
1236
    fill!(I, zer)
3,792✔
1237
    for i ∈ rows
164✔
1238
        I[i, i] = unit
661✔
1239
    end
1,158✔
1240
    I
164✔
1241
end
1242

1243
one(x::AbstractMatrix{T}) where {T} = _one(one(T), x)
139✔
1244
oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
31✔
1245

1246
## iteration support for arrays by iterating over `eachindex` in the array ##
1247
# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1248

1249
# While the definitions for IndexLinear are all simple enough to inline on their
1250
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1251
# inlining.
1252
function iterate(A::AbstractArray, state=(eachindex(A),))
19,620✔
1253
    y = iterate(state...)
139,288,110✔
1254
    y === nothing && return nothing
118,556,190✔
1255
    A[y[1]], (state[1], tail(y)...)
118,175,845✔
1256
end
1257

1258
isempty(a::AbstractArray) = (length(a) == 0)
2,147,483,647✔
1259

1260

1261
## range conversions ##
1262

1263
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
2✔
1264
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
162✔
1265
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
6✔
1266
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
1267
    LinRange(T(r.start), T(r.stop), length(r))
1✔
1268
end
1269

1270
## unsafe/pointer conversions ##
1271

1272
# note: the following type definitions don't mean any AbstractArray is convertible to
1273
# a data Ref. they just map the array element type to the pointer type for
1274
# convenience in cases that work.
1275
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
37,216,013✔
1276
function pointer(x::AbstractArray{T}, i::Integer) where T
102,749✔
1277
    @inline
373,227✔
1278
    pointer(x) + Int(_memory_offset(x, i))::Int
1,839,372✔
1279
end
1280

1281
# The distance from pointer(x) to the element at x[I...] in bytes
1282
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
1,523,260✔
1283
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
48,708✔
1284
    J = _to_subscript_indices(x, I...)
102,054✔
1285
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
383,661✔
1286
end
1287

1288
## Approach:
1289
# We only define one fallback method on getindex for all argument types.
1290
# That dispatches to an (inlined) internal _getindex function, where the goal is
1291
# to transform the indices such that we can call the only getindex method that
1292
# we require the type A{T,N} <: AbstractArray{T,N} to define; either:
1293
#       getindex(::A, ::Int) # if IndexStyle(A) == IndexLinear() OR
1294
#       getindex(::A{T,N}, ::Vararg{Int, N}) where {T,N} # if IndexCartesian()
1295
# If the subtype hasn't defined the required method, it falls back to the
1296
# _getindex function again where an error is thrown to prevent stack overflows.
1297
"""
1298
    getindex(A, inds...)
1299

1300
Return a subset of array `A` as selected by the indices `inds`.
1301

1302
Each index may be any [supported index type](@ref man-supported-index-types), such
1303
as an [`Integer`](@ref), [`CartesianIndex`](@ref), [range](@ref Base.AbstractRange), or [array](@ref man-multi-dim-arrays) of supported indices.
1304
A [:](@ref Base.Colon) may be used to select all elements along a specific dimension, and a boolean array (e.g. an `Array{Bool}` or a [`BitArray`](@ref)) may be used to filter for elements where the corresponding index is `true`.
1305

1306
When `inds` selects multiple elements, this function returns a newly
1307
allocated array. To index multiple elements without making a copy,
1308
use [`view`](@ref) instead.
1309

1310
See the manual section on [array indexing](@ref man-array-indexing) for details.
1311

1312
# Examples
1313
```jldoctest
1314
julia> A = [1 2; 3 4]
1315
2×2 Matrix{Int64}:
1316
 1  2
1317
 3  4
1318

1319
julia> getindex(A, 1)
1320
1
1321

1322
julia> getindex(A, [2, 1])
1323
2-element Vector{Int64}:
1324
 3
1325
 1
1326

1327
julia> getindex(A, 2:4)
1328
3-element Vector{Int64}:
1329
 3
1330
 2
1331
 4
1332

1333
julia> getindex(A, 2, 1)
1334
3
1335

1336
julia> getindex(A, CartesianIndex(2, 1))
1337
3
1338

1339
julia> getindex(A, :, 2)
1340
2-element Vector{Int64}:
1341
 2
1342
 4
1343

1344
julia> getindex(A, 2, :)
1345
2-element Vector{Int64}:
1346
 3
1347
 4
1348

1349
julia> getindex(A, A .> 2)
1350
2-element Vector{Int64}:
1351
 3
1352
 4
1353
```
1354
"""
1355
function getindex(A::AbstractArray, I...)
534,440✔
1356
    @_propagate_inbounds_meta
112,461,621✔
1357
    error_if_canonical_getindex(IndexStyle(A), A, I...)
112,461,621✔
1358
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
222,483,939✔
1359
end
1360
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1361
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
129,330,535✔
1362

1363
@inline unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
389✔
1364

1365
struct CanonicalIndexError <: Exception
1366
    func::String
1367
    type::Any
1368
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
14✔
1369
end
1370

1371
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1372
    throw(CanonicalIndexError("getindex", typeof(A)))
1373
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1374
    throw(CanonicalIndexError("getindex", typeof(A)))
UNCOV
1375
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
×
1376

1377
## Internal definitions
UNCOV
1378
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1379
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1380

1381
## IndexLinear Scalar indexing: canonical method is one Int
1382
_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)
43,818,612✔
1383
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
51✔
1384
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
342✔
1385
    @inline
2,374,600✔
1386
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
43,144,172✔
1387
    @inbounds r = getindex(A, _to_linear_index(A, I...))
43,144,104✔
1388
    r
2,374,549✔
1389
end
1390
_to_linear_index(A::AbstractArray, i::Integer) = i
51,891✔
1391
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
84,708,601✔
1392
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
330,488✔
1393
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
306,953,658✔
1394

1395
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1396
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
1397
    @inline
1,481,071✔
1398
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
1,481,144✔
1399
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
2,501,183✔
1400
    r
1,480,996✔
1401
end
1402
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
1403
    @_propagate_inbounds_meta
107,923,491✔
1404
    getindex(A, I...)
132,454,139✔
1405
end
1406
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
1,497,390✔
1407
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
UNCOV
1408
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1409
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
418✔
UNCOV
1410
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1411
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1412
    @inline
80,859✔
1413
    J, Jrem = IteratorsMD.split(I, Val(N))
80,859✔
1414
    _to_subscript_indices(A, J, Jrem)
80,859✔
1415
end
1416
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1417
    __to_subscript_indices(A, axes(A), J, Jrem)
1418
function __to_subscript_indices(A::AbstractArray,
1419
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1420
    @inline
2✔
1421
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1422
end
1423
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
80,857✔
1424
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
30,862✔
1425
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1426
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
UNCOV
1427
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1428
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
1,497,390✔
1429

1430
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1431
# function that allows dispatch on array storage
1432

1433
"""
1434
    setindex!(A, X, inds...)
1435
    A[inds...] = X
1436

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

1440
$(_DOCS_ALIASING_WARNING)
1441

1442
# Examples
1443
```jldoctest
1444
julia> A = zeros(2,2);
1445

1446
julia> setindex!(A, [10, 20], [1, 2]);
1447

1448
julia> A[[3, 4]] = [30, 40];
1449

1450
julia> A
1451
2×2 Matrix{Float64}:
1452
 10.0  30.0
1453
 20.0  40.0
1454
```
1455
"""
1456
function setindex!(A::AbstractArray, v, I...)
1,662✔
1457
    @_propagate_inbounds_meta
2,944,121✔
1458
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,944,121✔
1459
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
7,750,544✔
1460
end
1461
function unsafe_setindex!(A::AbstractArray, v, I...)
1462
    @inline
732✔
1463
    @inbounds r = setindex!(A, v, I...)
732✔
1464
    r
730✔
1465
end
1466

1467
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
7✔
1468
    throw(CanonicalIndexError("setindex!", typeof(A)))
1469
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1470
    throw(CanonicalIndexError("setindex!", typeof(A)))
UNCOV
1471
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
×
1472

1473
## Internal definitions
UNCOV
1474
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1475
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1476

1477
## IndexLinear Scalar indexing
1478
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
4,884,051✔
1479
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
624✔
1480
    @inline
158,586✔
1481
    @boundscheck checkbounds(A, I...)
260,603✔
1482
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
260,574✔
1483
    r
158,565✔
1484
end
1485

1486
# IndexCartesian Scalar indexing
1487
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
1488
    @_propagate_inbounds_meta
2,353,494✔
1489
    setindex!(A, v, I...)
2,353,501✔
1490
end
1491
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
1492
    @inline
23,691✔
1493
    @boundscheck checkbounds(A, I...)
23,696✔
1494
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
23,686✔
1495
    r
23,686✔
1496
end
1497

1498
function _unsetindex!(A::AbstractArray, i::Integer...)
UNCOV
1499
    @_propagate_inbounds_meta
×
UNCOV
1500
    _unsetindex!(A, map(to_index, i)...)
×
1501
end
1502

1503
function _unsetindex!(A::AbstractArray{T}, i::Int...) where T
1504
    # this provides a fallback method which is a no-op if the element is already unassigned
1505
    # such that copying into an uninitialized object generally always will work,
1506
    # even if the specific custom array type has not implemented `_unsetindex!`
1507
    @inline
10✔
1508
    @boundscheck checkbounds(A, i...)
10✔
1509
    allocatedinline(T) || @inbounds(!isassigned(A, i...)) || throw(MethodError(_unsetindex!, (A, i...)))
12✔
1510
    return A
8✔
1511
end
1512

1513
"""
1514
    parent(A)
1515

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

1521
# Examples
1522
```jldoctest
1523
julia> A = [1 2; 3 4]
1524
2×2 Matrix{Int64}:
1525
 1  2
1526
 3  4
1527

1528
julia> V = view(A, 1:2, :)
1529
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1530
 1  2
1531
 3  4
1532

1533
julia> parent(V)
1534
2×2 Matrix{Int64}:
1535
 1  2
1536
 3  4
1537
```
1538
"""
1539
function parent end
1540

1541
parent(a::AbstractArray) = a
1,552✔
1542

1543
## rudimentary aliasing detection ##
1544
"""
1545
    Base.unalias(dest, A)
1546

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

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

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

1557
See also [`Base.mightalias`](@ref).
1558
"""
1559
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
6,626,620✔
1560
unalias(dest, A::AbstractRange) = A
48,934,576✔
1561
unalias(dest, A) = A
3,188,559✔
1562

1563
"""
1564
    Base.unaliascopy(A)
1565

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

1569
This must return an object of the same type as `A` to preserve optimal performance in the
1570
much more common case where aliasing does not occur. By default,
1571
`unaliascopy(A::AbstractArray)` will attempt to use [`copy(A)`](@ref), but in cases where
1572
`copy(A)` is not a `typeof(A)`, then the array should provide a custom implementation of
1573
`Base.unaliascopy(A)`.
1574
"""
1575
unaliascopy(A::Array) = copy(A)
7,284✔
1576
unaliascopy(A::AbstractArray)::typeof(A) = (@noinline; _unaliascopy(A, copy(A)))
14✔
1577
_unaliascopy(A::T, C::T) where {T} = C
14✔
UNCOV
1578
_unaliascopy(A, C) = throw(ArgumentError("""
×
1579
    an array of type `$(typename(typeof(A)).wrapper)` shares memory with another argument
1580
    and must make a preventative copy of itself in order to maintain consistent semantics,
1581
    but `copy(::$(typeof(A)))` returns a new array of type `$(typeof(C))`.
1582
    To fix, implement:
1583
        `Base.unaliascopy(A::$(typename(typeof(A)).wrapper))::typeof(A)`"""))
UNCOV
1584
unaliascopy(A) = A
×
1585

1586
"""
1587
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1588

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

1591
By default, this simply checks if either of the arrays reference the same memory
1592
regions, as identified by their [`Base.dataids`](@ref).
1593
"""
1594
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B))
6,625,303✔
1595
mightalias(x, y) = false
×
1596

UNCOV
1597
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1598
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
UNCOV
1599
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
UNCOV
1600
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1601
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
6,413,481✔
1602
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
86,785✔
UNCOV
1603
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1604
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
5,528✔
1605
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
87,849✔
1606

1607
"""
1608
    Base.dataids(A::AbstractArray)
1609

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

1612
Custom arrays that would like to opt-in to aliasing detection of their component
1613
parts can specialize this method to return the concatenation of the `dataids` of
1614
their component parts.  A typical definition for an array that wraps a parent is
1615
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1616
"""
1617
dataids(A::AbstractArray) = (UInt(objectid(A)),)
474,428✔
1618
dataids(A::Memory) = (B = ccall(:jl_genericmemory_owner, Any, (Any,), A); (UInt(pointer(B isa typeof(A) ? B : A)),))
12,480,182✔
1619
dataids(A::Array) = dataids(A.ref.mem)
8,917,077✔
1620
dataids(::AbstractRange) = ()
2,577,988✔
1621
dataids(x) = ()
22,490✔
1622

1623
## get (getindex with a default value) ##
1624

1625
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1626
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1627

1628
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
365✔
1629
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
8✔
1630
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
15✔
1631
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
4✔
1632
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
7✔
1633
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
9✔
1634

1635
function get!(X::AbstractVector{T}, A::AbstractVector, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
×
1636
    # 1d is not linear indexing
1637
    ind = findall(in(axes1(A)), I)
×
UNCOV
1638
    X[ind] = A[I[ind]]
×
UNCOV
1639
    Xind = axes1(X)
×
UNCOV
1640
    X[first(Xind):first(ind)-1] = default
×
UNCOV
1641
    X[last(ind)+1:last(Xind)] = default
×
UNCOV
1642
    X
×
1643
end
1644
function get!(X::AbstractArray{T}, A::AbstractArray, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
1✔
1645
    # Linear indexing
1646
    ind = findall(in(1:length(A)), I)
1✔
1647
    X[ind] = A[I[ind]]
5✔
1648
    fill!(view(X, 1:first(ind)-1), default)
6✔
1649
    fill!(view(X, last(ind)+1:length(X)), default)
1✔
1650
    X
1✔
1651
end
1652

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

1655
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
2✔
1656
    fill!(X, default)
72✔
1657
    dst, src = indcopy(size(A), I)
2✔
1658
    X[dst...] = A[src...]
2✔
1659
    X
2✔
1660
end
1661

1662
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1663
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1664

1665
## structured matrix methods ##
1666
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
23,981✔
1667
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
33,019✔
1668

1669
## Concatenation ##
1670
eltypeof(x) = typeof(x)
14,701✔
1671
eltypeof(x::AbstractArray) = eltype(x)
14,644✔
1672

UNCOV
1673
promote_eltypeof() = error()
×
UNCOV
1674
promote_eltypeof(v1) = eltypeof(v1)
×
1675
promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2))
1,383✔
1676
promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...))
26,680✔
1677
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
6,870✔
1678
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
20✔
1679

UNCOV
1680
promote_eltype() = error()
×
UNCOV
1681
promote_eltype(v1) = eltype(v1)
×
1682
promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2))
1,780✔
1683
promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...))
515✔
1684
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
178✔
1685
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
1,555✔
1686

1687
#TODO: ERROR CHECK
1688
_cat(catdim::Int) = Vector{Any}()
1✔
1689

1690
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1691
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1692

1693
## cat: special cases
1694
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
158✔
1695
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
234✔
1696
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
97✔
1697
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
8,000,548✔
1698

1699
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
1✔
1700
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
2✔
1701
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
10✔
1702
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
61✔
1703

1704
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
5✔
1705
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
9✔
1706

1707
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1708
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1709
# but that solution currently fails (see #27188 and #27224)
1710
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1711

1712
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
1,499,919✔
1713
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
1,545,433✔
1714
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1715

1716
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
791,069✔
1717
    pos = 1
796,475✔
1718
    for k=1:Int(length(V))::Int
796,475✔
1719
        Vk = V[k]
797,882✔
1720
        p1 = pos + Int(length(Vk))::Int - 1
798,385✔
1721
        a[pos:p1] = Vk
5,805,777✔
1722
        pos = p1+1
797,882✔
1723
    end
799,289✔
1724
    a
796,475✔
1725
end
1726

1727
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
1,036✔
1728

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

1736

1737
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
299✔
1738
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
272✔
1739

1740
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1,042✔
1741
    nargs = length(A)
1,042✔
1742
    nrows = size(A[1], 1)
1,042✔
1743
    ncols = 0
1,042✔
1744
    dense = true
1,042✔
1745
    for j = 1:nargs
1,042✔
1746
        Aj = A[j]
2,147✔
1747
        if size(Aj, 1) != nrows
2,937✔
1748
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1749
        end
1750
        dense &= isa(Aj,Array)
2,146✔
1751
        nd = ndims(Aj)
2,935✔
1752
        ncols += (nd==2 ? size(Aj,2) : 1)
2,627✔
1753
    end
3,251✔
1754
    B = similar(A[1], T, nrows, ncols)
1,628✔
1755
    pos = 1
1,041✔
1756
    if dense
1,041✔
1757
        for k=1:nargs
406✔
1758
            Ak = A[k]
836✔
1759
            n = length(Ak)
1,060✔
1760
            copyto!(B, pos, Ak, 1, n)
1,416✔
1761
            pos += n
836✔
1762
        end
1,266✔
1763
    else
1764
        for k=1:nargs
635✔
1765
            Ak = A[k]
1,309✔
1766
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
1,582✔
1767
            B[:, pos:p1] = Ak
1,711✔
1768
            pos = p1+1
1,309✔
1769
        end
1,847✔
1770
    end
1771
    return B
1,041✔
1772
end
1773

1774
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
67✔
1775
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
202✔
1776

1777
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
491✔
1778
    nargs = length(A)
503✔
1779
    nrows = sum(a->size(a, 1), A)::Int
1,642✔
1780
    ncols = size(A[1], 2)
503✔
1781
    for j = 2:nargs
503✔
1782
        if size(A[j], 2) != ncols
607✔
1783
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1784
        end
1785
    end
682✔
1786
    B = similar(A[1], T, nrows, ncols)
903✔
1787
    pos = 1
502✔
1788
    for k=1:nargs
502✔
1789
        Ak = A[k]
1,088✔
1790
        p1 = pos+size(Ak,1)::Int-1
1,271✔
1791
        B[pos:p1, :] = Ak
1,144✔
1792
        pos = p1+1
1,088✔
1793
    end
1,674✔
1794
    return B
502✔
1795
end
1796

1797
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
1,545,930✔
1798

1799
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1800
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1801

1802
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1803
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1804

1805
## cat: general case
1806

1807
# helper functions
1808
cat_size(A) = (1,)
22,599✔
1809
cat_size(A::AbstractArray) = size(A)
16,332✔
UNCOV
1810
cat_size(A, d) = 1
×
1811
cat_size(A::AbstractArray, d) = size(A, d)
29,748✔
1812

UNCOV
1813
cat_length(::Any) = 1
×
1814
cat_length(a::AbstractArray) = length(a)
472✔
1815

UNCOV
1816
cat_ndims(a) = 0
×
1817
cat_ndims(a::AbstractArray) = ndims(a)
684✔
1818

1819
cat_indices(A, d) = OneTo(1)
22,600✔
1820
cat_indices(A::AbstractArray, d) = axes(A, d)
17,855✔
1821

1822
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,543✔
1823
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1824
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,681✔
1825
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1826
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
853✔
1827
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1828

1829
# These are for backwards compatibility (even though internal)
UNCOV
1830
cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
×
1831
function cat_shape(dims, shapes::Tuple)
4✔
1832
    out_shape = ()
4✔
1833
    for s in shapes
4✔
1834
        out_shape = _cshp(1, dims, out_shape, s)
18✔
1835
    end
15✔
1836
    return out_shape
4✔
1837
end
1838
# The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1839
cat_size_shape(dims) = ntuple(zero, Val(length(dims)))
×
1840
@inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
9,327✔
1841
_cat_size_shape(dims, shape) = shape
1,471✔
1842
@inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
29,767✔
1843

UNCOV
1844
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1845
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
20✔
1846
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
527✔
1847
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
499✔
1848
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1849
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
2,307✔
1850
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1851
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
1852
    _cs(ndim, shape[1], 1)
23✔
1853
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
19✔
1854
end
1855
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
1856
    next = _cs(ndim, shape[1], nshape[1])
158✔
1857
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
158✔
1858
end
1859
@inline function _cshp(ndim::Int, dims, shape, nshape)
86✔
1860
    a = shape[1]
30,566✔
1861
    b = nshape[1]
30,566✔
1862
    next = dims[1] ? a + b : _cs(ndim, a, b)
31,070✔
1863
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
30,644✔
1864
end
1865

1866
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,085✔
1867
    "mismatch in dimension $d (expected $a got $b)")))
1868

1869
dims2cat(::Val{dims}) where dims = dims2cat(dims)
544✔
1870
function dims2cat(dims)
776✔
1871
    if any(≤(0), dims)
2,956✔
1872
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1873
    end
1874
    ntuple(in(dims), maximum(dims))
1,401✔
1875
end
1876

1877
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
8,251✔
1878

1879
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
7,937✔
1880
    catdims = dims2cat(dims)
9,233✔
1881
    shape = cat_size_shape(catdims, X...)
9,327✔
1882
    A = cat_similar(X[1], T, shape)
10,036✔
1883
    if count(!iszero, catdims)::Int > 1
9,187✔
1884
        fill!(A, zero(T))
791✔
1885
    end
1886
    return __cat(A, shape, catdims, X...)
9,268✔
1887
end
1888
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1889
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
UNCOV
1890
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1891

1892
# Why isn't this called `__cat!`?
1893
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
9,780✔
1894

1895
function __cat_offset!(A, shape, catdims, offsets, x, X...)
36,081✔
1896
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1897
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
84,254✔
1898
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
39,019✔
1899
end
1900
__cat_offset!(A, shape, catdims, offsets) = A
9,189✔
1901

1902
function __cat_offset1!(A, shape, catdims, offsets, x)
5✔
1903
    inds = ntuple(length(offsets)) do i
39,201✔
1904
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
42,671✔
1905
    end
1906
    _copy_or_fill!(A, inds, x)
131,344✔
1907
    newoffsets = ntuple(length(offsets)) do i
39,003✔
1908
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
41,378✔
1909
    end
1910
    return newoffsets
39,003✔
1911
end
1912

1913
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
23,552✔
1914
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
107,756✔
1915

1916
"""
1917
    vcat(A...)
1918

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

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

1925
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1926

1927
# Examples
1928
```jldoctest
1929
julia> v = vcat([1,2], [3,4])
1930
4-element Vector{Int64}:
1931
 1
1932
 2
1933
 3
1934
 4
1935

1936
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1937
true
1938

1939
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1940
true
1941

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

1945
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1946
3-element Vector{Float64}:
1947
 1.0
1948
 1.5
1949
 2.0
1950

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

1954
julia> vcat(two...)
1955
3×3 Matrix{Float64}:
1956
 10.0  20.0  30.0
1957
  4.0   5.0   6.0
1958
  7.0   8.0   9.0
1959

1960
julia> vs = [[1, 2], [3, 4], [5, 6]];
1961

1962
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1963
6-element Vector{Int64}:
1964
 1
1965
 2
1966
 3
1967
 4
1968
 5
1969
 6
1970

1971
julia> ans == collect(Iterators.flatten(vs))
1972
true
1973
```
1974
"""
1975
vcat(X...) = cat(X...; dims=Val(1))
434✔
1976
"""
1977
    hcat(A...)
1978

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

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

1986
See also [`vcat`](@ref), [`hvcat`](@ref).
1987

1988
# Examples
1989
```jldoctest
1990
julia> hcat([1,2], [3,4], [5,6])
1991
2×3 Matrix{Int64}:
1992
 1  3  5
1993
 2  4  6
1994

1995
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1996
1×7 Matrix{Int64}:
1997
 1  2  30  40  5  6  7
1998

1999
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
2000
true
2001

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

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

2008
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
2009
2×6 Matrix{Float64}:
2010
 0.0  0.0  1.0  2.0  50.0  60.0
2011
 0.0  0.0  3.0  4.0  70.0  80.0
2012

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

2016
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
2017
0×3 Matrix{Int64}
2018

2019
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
2020
2×1 Matrix{Any}:
2021
 1.1
2022
 9.9
2023
```
2024
"""
2025
hcat(X...) = cat(X...; dims=Val(2))
10✔
2026

2027
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
338✔
2028
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
338✔
2029

2030
"""
2031
    cat(A...; dims)
2032

2033
Concatenate the input arrays along the dimensions specified in `dims`.
2034

2035
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
2036
a in A)`.
2037
Along other dimensions, all input arrays should have the same size,
2038
which will also be the size of the output array along those dimensions.
2039

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

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

2049
The keyword also accepts `Val(dims)`.
2050

2051
!!! compat "Julia 1.8"
2052
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
2053

2054
# Examples
2055

2056
Concatenate two arrays in different dimensions:
2057
```jldoctest
2058
julia> a = [1 2 3]
2059
1×3 Matrix{Int64}:
2060
 1  2  3
2061

2062
julia> b = [4 5 6]
2063
1×3 Matrix{Int64}:
2064
 4  5  6
2065

2066
julia> cat(a, b; dims=1)
2067
2×3 Matrix{Int64}:
2068
 1  2  3
2069
 4  5  6
2070

2071
julia> cat(a, b; dims=2)
2072
1×6 Matrix{Int64}:
2073
 1  2  3  4  5  6
2074

2075
julia> cat(a, b; dims=(1, 2))
2076
2×6 Matrix{Int64}:
2077
 1  2  3  0  0  0
2078
 0  0  0  4  5  6
2079
```
2080

2081
# Extended Help
2082

2083
Concatenate 3D arrays:
2084
```jldoctest
2085
julia> a = ones(2, 2, 3);
2086

2087
julia> b = ones(2, 2, 4);
2088

2089
julia> c = cat(a, b; dims=3);
2090

2091
julia> size(c) == (2, 2, 7)
2092
true
2093
```
2094

2095
Concatenate arrays of different sizes:
2096
```jldoctest
2097
julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2)  # same as hcat
2098
2×6×1 Array{Float64, 3}:
2099
[:, :, 1] =
2100
 1.0  2.0  3.14159  10.0  10.0  10.0
2101
 3.0  4.0  3.14159  10.0  10.0  10.0
2102
```
2103

2104
Construct a block diagonal matrix:
2105
```
2106
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
2107
4×7 Matrix{Bool}:
2108
 1  0  0  0  0  0  0
2109
 0  1  1  0  0  0  0
2110
 0  1  1  0  0  0  0
2111
 0  0  0  1  1  1  1
2112
```
2113

2114
```
2115
julia> cat(1, [2], [3;;]; dims=Val(2))
2116
1×3 Matrix{Int64}:
2117
 1  2  3
2118
```
2119

2120
!!! note
2121
    `cat` does not join two strings, you may want to use `*`.
2122

2123
```jldoctest
2124
julia> a = "aaa";
2125

2126
julia> b = "bbb";
2127

2128
julia> cat(a, b; dims=1)
2129
2-element Vector{String}:
2130
 "aaa"
2131
 "bbb"
2132

2133
julia> cat(a, b; dims=2)
2134
1×2 Matrix{String}:
2135
 "aaa"  "bbb"
2136

2137
julia> a * b
2138
"aaabbb"
2139
```
2140
"""
2141
@inline cat(A...; dims) = _cat(dims, A...)
17,379✔
2142
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
2143
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
219✔
2144

2145
# The specializations for 1 and 2 inputs are important
2146
# especially when running with --inline=no, see #11158
2147
vcat(A::AbstractArray) = cat(A; dims=Val(1))
1✔
2148
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
5✔
UNCOV
2149
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
2150
vcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(1))
7,074✔
2151
hcat(A::AbstractArray) = cat(A; dims=Val(2))
1✔
2152
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
1✔
2153
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
1✔
2154
hcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(2))
6✔
2155

2156
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
2157
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2158
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
2159
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2160
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
2161
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
2162

2163
# 2d horizontal and vertical concatenation
2164

2165
# these are produced in lowering if splatting occurs inside hvcat
2166
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
3✔
2167
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
3✔
2168

2169
function hvcat(nbc::Int, as...)
10✔
2170
    # nbc = # of block columns
2171
    n = length(as)
10✔
2172
    mod(n,nbc) != 0 &&
20✔
2173
        throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
2174
    nbr = div(n,nbc)
9✔
2175
    hvcat(ntuple(Returns(nbc), nbr), as...)
9✔
2176
end
2177

2178
"""
2179
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2180

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

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

2191
julia> [a b c; d e f]
2192
2×3 Matrix{Int64}:
2193
 1  2  3
2194
 4  5  6
2195

2196
julia> hvcat((3,3), a,b,c,d,e,f)
2197
2×3 Matrix{Int64}:
2198
 1  2  3
2199
 4  5  6
2200

2201
julia> [a b; c d; e f]
2202
3×2 Matrix{Int64}:
2203
 1  2
2204
 3  4
2205
 5  6
2206

2207
julia> hvcat((2,2,2), a,b,c,d,e,f)
2208
3×2 Matrix{Int64}:
2209
 1  2
2210
 3  4
2211
 5  6
2212
julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f)
2213
true
2214
```
2215
"""
2216
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
323✔
2217
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray{T}...) where {T} = typed_hvcat(T, rows, xs...)
518✔
2218

2219
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T
882✔
2220
    nbr = length(rows)  # number of block rows
882✔
2221

2222
    nc = 0
882✔
2223
    for i=1:rows[1]
882✔
2224
        nc += size(as[i],2)
1,697✔
2225
    end
2,512✔
2226

2227
    nr = 0
882✔
2228
    a = 1
882✔
2229
    for i = 1:nbr
882✔
2230
        nr += size(as[a],1)
1,427✔
2231
        a += rows[i]
1,427✔
2232
    end
1,972✔
2233

2234
    out = similar(as[1], T, nr, nc)
924✔
2235

2236
    a = 1
882✔
2237
    r = 1
882✔
2238
    for i = 1:nbr
882✔
2239
        c = 1
1,427✔
2240
        szi = size(as[a],1)
1,427✔
2241
        for j = 1:rows[i]
1,427✔
2242
            Aj = as[a+j-1]
2,631✔
2243
            szj = size(Aj,2)
2,631✔
2244
            if size(Aj,1) != szi
2,631✔
2245
                throw(DimensionMismatch("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
1✔
2246
            end
2247
            if c-1+szj > nc
3,927✔
2248
                throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
1✔
2249
            end
2250
            out[r:r-1+szi, c:c-1+szj] = Aj
3,845✔
2251
            c += szj
2,629✔
2252
        end
3,833✔
2253
        if c != nc+1
1,425✔
2254
            throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
1✔
2255
        end
2256
        r += szi
1,424✔
2257
        a += rows[i]
1,424✔
2258
    end
1,969✔
2259
    out
879✔
2260
end
2261

2262
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
UNCOV
2263
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2264

2265
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,310✔
2266
    nr = length(rows)
1,310✔
2267
    nc = rows[1]
1,310✔
2268

2269
    a = Matrix{T}(undef, nr, nc)
2,620✔
2270
    if length(a) != length(xs)
1,310✔
2271
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2272
    end
2273
    k = 1
1,308✔
2274
    @inbounds for i=1:nr
1,308✔
2275
        if nc != rows[i]
3,538✔
2276
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2277
        end
2278
        for j=1:nc
3,537✔
2279
            a[i,j] = xs[k]
9,674✔
2280
            k += 1
9,674✔
2281
        end
15,811✔
2282
    end
5,767✔
2283
    a
1,307✔
2284
end
2285

2286
function hvcat_fill!(a::Array, xs::Tuple)
490✔
2287
    nr, nc = size(a,1), size(a,2)
498✔
2288
    len = length(xs)
498✔
2289
    if nr*nc != len
498✔
2290
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2291
    end
2292
    k = 1
497✔
2293
    for i=1:nr
497✔
2294
        @inbounds for j=1:nc
1,328✔
2295
            a[i,j] = xs[k]
8,804✔
2296
            k += 1
8,804✔
2297
        end
16,280✔
2298
    end
2,159✔
2299
    a
497✔
2300
end
2301

2302
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
177✔
2303
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
138✔
2304
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2305
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
3✔
2306

2307
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
350✔
2308
    nr = length(rows)
426✔
2309
    nc = rows[1]
426✔
2310
    for i = 2:nr
426✔
2311
        if nc != rows[i]
820✔
2312
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2313
        end
2314
    end
1,212✔
2315
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
424✔
2316
end
2317

2318
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T
153✔
2319
    nbr = length(rows)  # number of block rows
153✔
2320
    rs = Vector{Any}(undef, nbr)
153✔
2321
    a = 1
153✔
2322
    for i = 1:nbr
153✔
2323
        rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...)
376✔
2324
        a += rows[i]
376✔
2325
    end
599✔
2326
    T[rs...;]
153✔
2327
end
2328

2329
## N-dimensional concatenation ##
2330

2331
"""
2332
    hvncat(dim::Int, row_first, values...)
2333
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2334
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2335

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

2338
This function is called for block matrix syntax. The first argument either specifies the
2339
shape of the concatenation, similar to `hvcat`, as a tuple of tuples, or the dimensions that
2340
specify the key number of elements along each axis, and is used to determine the output
2341
dimensions. The `dims` form is more performant, and is used by default when the concatenation
2342
operation has the same number of elements along each axis (e.g., [a b; c d;;; e f ; g h]).
2343
The `shape` form is used when the number of elements along each axis is unbalanced
2344
(e.g., [a b ; c]). Unbalanced syntax needs additional validation overhead. The `dim` form
2345
is an optimization for concatenation along just one dimension. `row_first` indicates how
2346
`values` are ordered. The meaning of the first and second elements of `shape` are also
2347
swapped based on `row_first`.
2348

2349
# Examples
2350
```jldoctest
2351
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2352
(1, 2, 3, 4, 5, 6)
2353

2354
julia> [a b c;;; d e f]
2355
1×3×2 Array{Int64, 3}:
2356
[:, :, 1] =
2357
 1  2  3
2358

2359
[:, :, 2] =
2360
 4  5  6
2361

2362
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2363
2×1×3 Array{Int64, 3}:
2364
[:, :, 1] =
2365
 1
2366
 2
2367

2368
[:, :, 2] =
2369
 3
2370
 4
2371

2372
[:, :, 3] =
2373
 5
2374
 6
2375

2376
julia> [a b;;; c d;;; e f]
2377
1×2×3 Array{Int64, 3}:
2378
[:, :, 1] =
2379
 1  2
2380

2381
[:, :, 2] =
2382
 3  4
2383

2384
[:, :, 3] =
2385
 5  6
2386

2387
julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2388
1×3×2 Array{Int64, 3}:
2389
[:, :, 1] =
2390
 1  2  3
2391

2392
[:, :, 2] =
2393
 4  5  6
2394
```
2395

2396
# Examples for construction of the arguments
2397
```
2398
[a b c ; d e f ;;;
2399
 g h i ; j k l ;;;
2400
 m n o ; p q r ;;;
2401
 s t u ; v w x]
2402
⇒ dims = (2, 3, 4)
2403

2404
[a b ; c ;;; d ;;;;]
2405
 ___   _     _
2406
 2     1     1 = elements in each row (2, 1, 1)
2407
 _______     _
2408
 3           1 = elements in each column (3, 1)
2409
 _____________
2410
 4             = elements in each 3d slice (4,)
2411
 _____________
2412
 4             = elements in each 4d slice (4,)
2413
⇒ shape = ((2, 1, 1), (3, 1), (4,), (4,)) with `row_first` = true
2414
```
2415
"""
2416
hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...)
262✔
2417
hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...)
78✔
2418

2419
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
28✔
2420
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
91✔
2421
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
89✔
UNCOV
2422
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
UNCOV
2423
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2424
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
132✔
2425

2426

2427
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2428
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2429

2430
# 1-dimensional hvncat methods
2431

2432
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
4✔
2433
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2434
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
4✔
2435
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
4✔
UNCOV
2436
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2437
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
4✔
UNCOV
2438
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2439

2440
_typed_hvncat_0d_only_one() =
8✔
2441
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2442

2443
# `@constprop :aggressive` here to form constant `Val(dim)` type to get type stability
2444
@constprop :aggressive _typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters
78✔
2445

2446
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
15✔
2447
    N < 0 &&
15✔
2448
        throw(ArgumentError("concatenation dimension must be non-negative"))
2449
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
14✔
2450
end
2451

2452
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
26✔
2453
    N < 0 &&
39✔
2454
        throw(ArgumentError("concatenation dimension must be non-negative"))
2455
    A = cat_similar(xs[1], T, (ntuple(x -> 1, Val(N - 1))..., length(xs)))
38✔
2456
    hvncat_fill!(A, false, xs)
38✔
2457
    return A
38✔
2458
end
2459

2460
function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
24✔
2461
    # optimization for arrays that can be concatenated by copying them linearly into the destination
2462
    # conditions: the elements must all have 1-length dimensions above N
2463
    length(as) > 0 ||
25✔
2464
        throw(ArgumentError("must have at least one element"))
2465
    N < 0 &&
25✔
2466
        throw(ArgumentError("concatenation dimension must be non-negative"))
2467
    for a ∈ as
23✔
2468
        ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) ||
61✔
2469
            return _typed_hvncat(T, (ntuple(x -> 1, Val(N - 1))..., length(as), 1), false, as...)
2470
            # the extra 1 is to avoid an infinite cycle
2471
    end
46✔
2472

2473
    nd = N
17✔
2474

2475
    Ndim = 0
17✔
2476
    for i ∈ eachindex(as)
17✔
2477
        Ndim += cat_size(as[i], N)
38✔
2478
        nd = max(nd, cat_ndims(as[i]))
38✔
2479
        for d ∈ 1:N - 1
32✔
2480
            cat_size(as[1], d) == cat_size(as[i], d) || throw(DimensionMismatch("mismatched size along axis $d in element $i"))
39✔
2481
        end
44✔
2482
    end
43✔
2483

2484
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
32✔
2485
    k = 1
13✔
2486
    for a ∈ as
13✔
2487
        for i ∈ eachindex(a)
26✔
2488
            A[k] = a[i]
34✔
2489
            k += 1
34✔
2490
        end
47✔
2491
    end
34✔
2492
    return A
13✔
2493
end
2494

2495
function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
14✔
2496
    length(as) > 0 ||
14✔
2497
        throw(ArgumentError("must have at least one element"))
2498
    N < 0 &&
14✔
2499
        throw(ArgumentError("concatenation dimension must be non-negative"))
2500
    nd = N
12✔
2501
    Ndim = 0
12✔
2502
    for i ∈ eachindex(as)
12✔
2503
        Ndim += cat_size(as[i], N)
30✔
2504
        nd = max(nd, cat_ndims(as[i]))
34✔
2505
        for d ∈ 1:N-1
20✔
2506
            cat_size(as[i], d) == 1 ||
36✔
2507
                throw(DimensionMismatch("all dimensions of element $i other than $N must be of length 1"))
2508
        end
28✔
2509
    end
20✔
2510

2511
    A = Array{T, nd}(undef, ntuple(x -> 1, Val(N - 1))..., Ndim, ntuple(x -> 1, nd - N)...)
7✔
2512

2513
    k = 1
4✔
2514
    for a ∈ as
4✔
2515
        if a isa AbstractArray
12✔
2516
            lena = length(a)
2✔
2517
            copyto!(A, k, a, 1, lena)
2✔
2518
            k += lena
2✔
2519
        else
2520
            A[k] = a
10✔
2521
            k += 1
10✔
2522
        end
2523
    end
16✔
2524
    return A
4✔
2525
end
2526

2527
# 0-dimensional cases for balanced and unbalanced hvncat method
2528

2529
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2530
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2531

2532

2533
# balanced dimensions hvncat methods
2534

2535
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
2✔
2536
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as::Number...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
7✔
2537

2538
function _typed_hvncat_1d(::Type{T}, ds::Int, ::Val{row_first}, as...) where {T, row_first}
21✔
2539
    lengthas = length(as)
22✔
2540
    ds > 0 ||
22✔
2541
        throw(ArgumentError("`dimsshape` argument must consist of positive integers"))
2542
    lengthas == ds ||
30✔
2543
        throw(ArgumentError("number of elements does not match `dimshape` argument; expected $ds, got $lengthas"))
2544
    if row_first
14✔
2545
        return _typed_hvncat(T, Val(2), as...)
4✔
2546
    else
2547
        return _typed_hvncat(T, Val(1), as...)
10✔
2548
    end
2549
end
2550

2551
function _typed_hvncat(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, xs::Number...) where {T, N}
44✔
2552
    all(>(0), dims) ||
60✔
2553
        throw(ArgumentError("`dims` argument must contain positive integers"))
2554
    A = Array{T, N}(undef, dims...)
56✔
2555
    lengtha = length(A)  # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations
28✔
2556
    lengthx = length(xs) # Cuts from 3 allocations to 1.
28✔
2557
    if lengtha != lengthx
28✔
UNCOV
2558
       throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)"))
×
2559
    end
2560
    hvncat_fill!(A, row_first, xs)
28✔
2561
    return A
28✔
2562
end
2563

2564
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
66✔
2565
    nr, nc = size(A, 1), size(A, 2)
66✔
2566
    na = prod(size(A)[3:end])
66✔
2567
    len = length(xs)
66✔
2568
    nrc = nr * nc
66✔
2569
    if nrc * na != len
66✔
UNCOV
2570
        throw(ArgumentError("argument count $(len) does not match specified shape $(size(A))"))
×
2571
    end
2572
    # putting these in separate functions leads to unnecessary allocations
2573
    if row_first
66✔
2574
        k = 1
17✔
2575
        for d ∈ 1:na
17✔
2576
            dd = nrc * (d - 1)
31✔
2577
            for i ∈ 1:nr
31✔
2578
                Ai = dd + i
42✔
2579
                for j ∈ 1:nc
42✔
2580
                    @inbounds A[Ai] = xs[k]
95✔
2581
                    k += 1
95✔
2582
                    Ai += nr
95✔
2583
                end
148✔
2584
            end
53✔
2585
        end
31✔
2586
    else
2587
        for k ∈ eachindex(xs)
49✔
2588
            @inbounds A[k] = xs[k]
96✔
2589
        end
96✔
2590
    end
2591
end
2592

2593
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
76✔
2594
    # function barrier after calculating the max is necessary for high performance
2595
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
90✔
2596
    return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
90✔
2597
end
2598

2599
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
90✔
2600
    length(as) > 0 ||
90✔
2601
        throw(ArgumentError("must have at least one element"))
2602
    all(>(0), dims) ||
122✔
2603
        throw(ArgumentError("`dims` argument must contain positive integers"))
2604

2605
    d1 = row_first ? 2 : 1
58✔
2606
    d2 = row_first ? 1 : 2
58✔
2607

2608
    outdims = zeros(Int, N)
203✔
2609

2610
    # validate shapes for lowest level of concatenation
2611
    d = findfirst(>(1), dims)
86✔
2612
    if d !== nothing # all dims are 1
58✔
2613
        if row_first && d < 3
57✔
2614
            d = d == 1 ? 2 : 1
32✔
2615
        end
2616
        nblocks = length(as) ÷ dims[d]
57✔
2617
        for b ∈ 1:nblocks
57✔
2618
            offset = ((b - 1) * dims[d])
175✔
2619
            startelementi = offset + 1
175✔
2620
            for i ∈ offset .+ (2:dims[d])
263✔
2621
                for dd ∈ 1:N
111✔
2622
                    dd == d && continue
316✔
2623
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
313✔
2624
                        throw(DimensionMismatch("incompatible shape in element $i"))
6✔
2625
                    end
2626
                end
515✔
2627
            end
129✔
2628
        end
287✔
2629
    end
2630

2631
    # discover number of rows or columns
2632
    for i ∈ 1:dims[d1]
52✔
2633
        outdims[d1] += cat_size(as[i], d1)
108✔
2634
    end
164✔
2635

2636
    currentdims = zeros(Int, N)
176✔
2637
    blockcount = 0
52✔
2638
    elementcount = 0
52✔
2639
    for i ∈ eachindex(as)
52✔
2640
        elementcount += cat_length(as[i])
306✔
2641
        currentdims[d1] += cat_size(as[i], d1)
259✔
2642
        if currentdims[d1] == outdims[d1]
259✔
2643
            currentdims[d1] = 0
129✔
2644
            for d ∈ (d2, 3:N...)
129✔
2645
                currentdims[d] += cat_size(as[i], d)
203✔
2646
                if outdims[d] == 0 # unfixed dimension
203✔
2647
                    blockcount += 1
167✔
2648
                    if blockcount == dims[d]
167✔
2649
                        outdims[d] = currentdims[d]
88✔
2650
                        currentdims[d] = 0
88✔
2651
                        blockcount = 0
88✔
2652
                    else
2653
                        break
79✔
2654
                    end
2655
                else # fixed dimension
2656
                    if currentdims[d] == outdims[d] # end of dimension
36✔
2657
                        currentdims[d] = 0
23✔
2658
                    elseif currentdims[d] < outdims[d] # dimension in progress
13✔
2659
                        break
13✔
2660
                    else # exceeded dimension
UNCOV
2661
                        throw(DimensionMismatch("argument $i has too many elements along axis $d"))
×
2662
                    end
2663
                end
2664
            end
142✔
2665
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
130✔
2666
            throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
16✔
2667
        end
2668
    end
450✔
2669

2670
    outlen = prod(outdims)
72✔
2671
    elementcount == outlen ||
36✔
2672
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2673

2674
    # copy into final array
2675
    A = cat_similar(as[1], T, outdims)
36✔
2676
    # @assert all(==(0), currentdims)
2677
    outdims .= 0
108✔
2678
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
36✔
2679
    return A
36✔
2680
end
2681

2682

2683
# unbalanced dimensions hvncat methods
2684

2685
function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
19✔
2686
    length(shape[1]) > 0 ||
19✔
2687
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2688
    return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
13✔
2689
end
2690

2691
function _typed_hvncat(T::Type, shape::NTuple{N, Tuple}, row_first::Bool, as...) where {N}
99✔
2692
    # function barrier after calculating the max is necessary for high performance
2693
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
115✔
2694
    return _typed_hvncat_shape(T, (shape..., ntuple(x -> shape[end], nd - N)...), row_first, as)
122✔
2695
end
2696

2697
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
107✔
2698
    length(as) > 0 ||
107✔
2699
        throw(ArgumentError("must have at least one element"))
2700
    all(>(0), tuple((shape...)...)) ||
147✔
2701
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2702

2703
    d1 = row_first ? 2 : 1
67✔
2704
    d2 = row_first ? 1 : 2
67✔
2705

2706
    shapev = collect(shape) # saves allocations later
110✔
2707
    all(!isempty, shapev) ||
67✔
2708
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2709
    length(shapev[end]) == 1 ||
70✔
2710
        throw(ArgumentError("last level of shape must contain only one integer"))
2711
    shapelength = shapev[end][1]
64✔
2712
    lengthas = length(as)
64✔
2713
    shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)"))
64✔
2714
    # discover dimensions
2715
    nd = max(N, cat_ndims(as[1]))
64✔
2716
    outdims = fill(-1, nd)
210✔
2717
    currentdims = zeros(Int, nd)
210✔
2718
    blockcounts = zeros(Int, nd)
210✔
2719
    shapepos = ones(Int, nd)
210✔
2720

2721
    elementcount = 0
64✔
2722
    for i ∈ eachindex(as)
64✔
2723
        elementcount += cat_length(as[i])
355✔
2724
        wasstartblock = false
313✔
2725
        for d ∈ 1:N
313✔
2726
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
907✔
2727
            dsize = cat_size(as[i], ad)
1,386✔
2728
            blockcounts[d] += 1
907✔
2729

2730
            if d == 1 || i == 1 || wasstartblock
1,501✔
2731
                currentdims[d] += dsize
623✔
2732
            elseif dsize != cat_size(as[i - 1], ad)
422✔
2733
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
8✔
2734
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2735
            end
2736

2737
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
899✔
2738

2739
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
899✔
2740
            if isendblock
899✔
2741
                if outdims[d] == -1
269✔
2742
                    outdims[d] = currentdims[d]
138✔
2743
                elseif outdims[d] != currentdims[d]
131✔
2744
                    throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
40✔
2745
                                             expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2746
                end
2747
                currentdims[d] = 0
229✔
2748
                blockcounts[d] = 0
229✔
2749
                shapepos[d] += 1
229✔
2750
                d > 1 && (blockcounts[d - 1] == 0 ||
230✔
2751
                    throw(DimensionMismatch("shape in level $d is inconsistent; level counts must nest \
2752
                                             evenly into each other")))
2753
            end
2754
        end
1,452✔
2755
    end
513✔
2756

2757
    outlen = prod(outdims)
30✔
2758
    elementcount == outlen ||
15✔
2759
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2760

2761
    if row_first
15✔
2762
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2763
    end
2764

2765
    # @assert all(==(0), currentdims)
2766
    # @assert all(==(0), blockcounts)
2767

2768
    # copy into final array
2769
    A = cat_similar(as[1], T, outdims)
15✔
2770
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
15✔
2771
    return A
15✔
2772
end
2773

2774
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int},
51✔
2775
                              d1::Int, d2::Int, as::Tuple) where {T, N}
2776
    N > 1 || throw(ArgumentError("dimensions of the destination array must be at least 2"))
51✔
2777
    length(scratch1) == length(scratch2) == N ||
51✔
2778
        throw(ArgumentError("scratch vectors must have as many elements as the destination array has dimensions"))
2779
    0 < d1 < 3 &&
51✔
2780
    0 < d2 < 3 &&
2781
    d1 != d2 ||
2782
        throw(ArgumentError("d1 and d2 must be either 1 or 2, exclusive."))
2783
    outdims = size(A)
51✔
2784
    offsets = scratch1
51✔
2785
    inneroffsets = scratch2
51✔
2786
    for a ∈ as
51✔
2787
        if isa(a, AbstractArray)
270✔
2788
            for ai ∈ a
249✔
2789
                @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
7,046✔
2790
                A[Ai] = ai
1,888✔
2791

2792
                @inbounds for j ∈ 1:N
1,888✔
2793
                    inneroffsets[j] += 1
4,152✔
2794
                    inneroffsets[j] < cat_size(a, j) && break
7,976✔
2795
                    inneroffsets[j] = 0
2,490✔
2796
                end
2,490✔
2797
            end
1,912✔
2798
        else
2799
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2800
            A[Ai] = a
27✔
2801
        end
2802

2803
        @inbounds for j ∈ (d1, d2, 3:N...)
270✔
2804
            offsets[j] += cat_size(a, j)
518✔
2805
            offsets[j] < outdims[j] && break
518✔
2806
            offsets[j] = 0
304✔
2807
        end
304✔
2808
    end
270✔
2809
end
2810

2811
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
2812
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2813
    Ai = inneroffsets[1] + offsets[1] + 1
1,915✔
2814
    for j ∈ 2:nd
1,915✔
2815
        increment = inneroffsets[j] + offsets[j]
7,098✔
2816
        for k ∈ 1:j-1
7,098✔
2817
            increment *= outdims[k]
17,209✔
2818
        end
27,320✔
2819
        Ai += increment
7,098✔
2820
    end
12,281✔
2821
    Ai
1,915✔
2822
end
2823

2824
"""
2825
    stack(iter; [dims])
2826

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

2830
By default the axes of the elements are placed first,
2831
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2832
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2833

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

2838
The various [`cat`](@ref) functions also combine arrays. However, these all
2839
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2840
the arrays along new dimensions.
2841
They also accept arrays as separate arguments, rather than a single collection.
2842

2843
!!! compat "Julia 1.9"
2844
    This function requires at least Julia 1.9.
2845

2846
# Examples
2847
```jldoctest
2848
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2849

2850
julia> mat = stack(vecs)
2851
2×3 Matrix{Float32}:
2852
 1.0  30.0  500.0
2853
 2.0  40.0  600.0
2854

2855
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2856
true
2857

2858
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2859
true
2860

2861
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2862
2×4 Matrix{Int64}:
2863
  1   2   3   4
2864
 10  11  12  13
2865

2866
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2867
true
2868

2869
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2870
3×2 Matrix{Float32}:
2871
   1.0    2.0
2872
  30.0   40.0
2873
 500.0  600.0
2874

2875
julia> x = rand(3,4);
2876

2877
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2878
true
2879
```
2880

2881
Higher-dimensional examples:
2882

2883
```jldoctest
2884
julia> A = rand(5, 7, 11);
2885

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

2888
julia> (element = size(first(E)), container = size(E))
2889
(element = (5, 11), container = (7,))
2890

2891
julia> stack(E) |> size
2892
(5, 11, 7)
2893

2894
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2895
true
2896

2897
julia> A == stack(E; dims=2)
2898
true
2899

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

2902
julia> (element = size(first(M)), container = size(M))
2903
(element = (2, 3), container = (5, 7))
2904

2905
julia> stack(M) |> size  # keeps all dimensions
2906
(2, 3, 5, 7)
2907

2908
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2909
(35, 2, 3)
2910

2911
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2912
(14, 15)
2913
```
2914
"""
2915
stack(iter; dims=:) = _stack(dims, iter)
254✔
2916

2917
"""
2918
    stack(f, args...; [dims])
2919

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

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

2927
See also [`mapslices`](@ref), [`eachcol`](@ref).
2928

2929
# Examples
2930
```jldoctest
2931
julia> stack(c -> (c, c-32), "julia")
2932
2×5 Matrix{Char}:
2933
 'j'  'u'  'l'  'i'  'a'
2934
 'J'  'U'  'L'  'I'  'A'
2935

2936
julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2937
         vcat(row, row .* n, row ./ n)
2938
       end
2939
2×9 Matrix{Float64}:
2940
 1.0  2.0  3.0   10.0   20.0   30.0  0.1   0.2   0.3
2941
 4.0  5.0  6.0  400.0  500.0  600.0  0.04  0.05  0.06
2942
```
2943
"""
2944
stack(f, iter; dims=:) = _stack(dims, f(x) for x in iter)
12✔
2945
stack(f, xs, yzs...; dims=:) = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
2✔
2946

2947
_stack(dims::Union{Integer, Colon}, iter) = _stack(dims, IteratorSize(iter), iter)
169✔
2948

2949
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2950

2951
function _stack(dims, ::Union{HasShape, HasLength}, iter)
33✔
2952
    S = @default_eltype iter
122✔
2953
    T = S != Union{} ? eltype(S) : Any  # Union{} occurs for e.g. stack(1,2), postpone the error
122✔
2954
    if isconcretetype(T)
122✔
2955
        _typed_stack(dims, T, S, iter)
109✔
2956
    else  # Need to look inside, but shouldn't run an expensive iterator twice:
2957
        array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
38✔
2958
        isempty(array) && return _empty_stack(dims, T, S, iter)
38✔
2959
        T2 = mapreduce(eltype, promote_type, array)
35✔
2960
        _typed_stack(dims, T2, eltype(array), array)
36✔
2961
    end
2962
end
2963

2964
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
112✔
2965
    xit = iterate(A)
217✔
2966
    nothing === xit && return _empty_stack(:, T, S, A)
94✔
2967
    x1, _ = xit
94✔
2968
    ax1 = _iterator_axes(x1)
98✔
2969
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
173✔
2970
    off = firstindex(B)
93✔
2971
    len = length(x1)
99✔
2972
    while xit !== nothing
2,563✔
2973
        x, state = xit
2,476✔
2974
        _stack_size_check(x, ax1)
4,654✔
2975
        copyto!(B, off, x)
3,564✔
2976
        off += len
2,470✔
2977
        xit = iterate(A, state)
3,737✔
2978
    end
2,470✔
2979
    B
87✔
2980
end
2981

2982
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2983
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2984
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2985

2986
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2987
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
48✔
2988
    _typed_stack(dims, T, S, IteratorSize(S), A)
2989
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
13✔
2990
    _typed_stack(dims, T, S, HasShape{1}(), A)
2991
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
1✔
2992
    if dims == N+1
27✔
2993
        _typed_stack(:, T, S, A, (_vec_axis(A),))
4✔
2994
    else
2995
        _dim_stack(dims, T, S, A)
23✔
2996
    end
2997
end
2998
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
2✔
2999
    _dim_stack(dims, T, S, A)
3000

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

3003
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
25✔
3004
    xit = Iterators.peel(A)
48✔
3005
    nothing === xit && return _empty_stack(dims, T, S, A)
25✔
3006
    x1, xrest = xit
25✔
3007
    ax1 = _iterator_axes(x1)
25✔
3008
    N1 = length(ax1)+1
24✔
3009
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
27✔
3010

3011
    newaxis = _vec_axis(A)
21✔
3012
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
122✔
3013
    B = similar(_ensure_array(x1), T, outax...)
41✔
3014

3015
    if dims == 1
21✔
3016
        _dim_stack!(Val(1), B, x1, xrest)
13✔
3017
    elseif dims == 2
8✔
3018
        _dim_stack!(Val(2), B, x1, xrest)
4✔
3019
    else
3020
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
3021
    end
3022
    B
18✔
3023
end
3024

3025
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
3026
    before = ntuple(d -> Colon(), dims - 1)
29✔
3027
    after = ntuple(d -> Colon(), ndims(B) - dims)
42✔
3028

3029
    i = firstindex(B, dims)
21✔
3030
    copyto!(view(B, before..., i, after...), x1)
40✔
3031

3032
    for x in xrest
29✔
3033
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
3034
        i += 1
3,261✔
3035
        @inbounds copyto!(view(B, before..., i, after...), x)
6,415✔
3036
    end
3,261✔
3037
end
3038

3039
@inline function _stack_size_check(x, ax1::Tuple)
26✔
3040
    if _iterator_axes(x) != ax1
11,107✔
3041
        uax1 = map(UnitRange, ax1)
9✔
3042
        uaxN = map(UnitRange, axes(x))
9✔
3043
        throw(DimensionMismatch(
9✔
3044
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
3045
    end
3046
end
3047

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

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

3053

3054
## Reductions and accumulates ##
3055

3056
function isequal(A::AbstractArray, B::AbstractArray)
246,479✔
3057
    if A === B return true end
288,936✔
3058
    if axes(A) != axes(B)
574,340✔
3059
        return false
2,924✔
3060
    end
3061
    for (a, b) in zip(A, B)
570,839✔
3062
        if !isequal(a, b)
92,068,117✔
3063
            return false
623✔
3064
        end
3065
    end
183,686,539✔
3066
    return true
285,094✔
3067
end
3068

3069
function cmp(A::AbstractVector, B::AbstractVector)
43✔
3070
    for (a, b) in zip(A, B)
776✔
3071
        if !isequal(a, b)
1,009✔
3072
            return isless(a, b) ? -1 : 1
528✔
3073
        end
3074
    end
1,266✔
3075
    return cmp(length(A), length(B))
24✔
3076
end
3077

3078
"""
3079
    isless(A::AbstractVector, B::AbstractVector)
3080

3081
Return `true` when `A` is less than `B` in lexicographic order.
3082
"""
3083
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
506✔
3084

3085
function (==)(A::AbstractArray, B::AbstractArray)
6,552,623✔
3086
    if axes(A) != axes(B)
13,147,678✔
3087
        return false
3,582✔
3088
    end
3089
    anymissing = false
6,563,520✔
3090
    for (a, b) in zip(A, B)
12,257,220✔
3091
        eq = (a == b)
321,369,715✔
3092
        if ismissing(eq)
286,760,474✔
3093
            anymissing = true
24✔
3094
        elseif !eq
320,480,148✔
3095
            return false
2,804✔
3096
        end
3097
    end
635,272,361✔
3098
    return anymissing ? missing : true
6,569,287✔
3099
end
3100

3101
# _sub2ind and _ind2sub
3102
# fallbacks
3103
function _sub2ind(A::AbstractArray, I...)
263✔
3104
    @inline
291,152,237✔
3105
    _sub2ind(axes(A), I...)
306,953,658✔
3106
end
3107

3108
function _ind2sub(A::AbstractArray, ind)
3109
    @inline
1,497,391✔
3110
    _ind2sub(axes(A), ind)
1,497,391✔
3111
end
3112

3113
# 0-dimensional arrays and indexing with []
UNCOV
3114
_sub2ind(::Tuple{}) = 1
×
UNCOV
3115
_sub2ind(::DimsInteger) = 1
×
UNCOV
3116
_sub2ind(::Indices) = 1
×
3117
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
16✔
3118

3119
# Generic cases
3120
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
5,483,092✔
3121
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
307,071,561✔
3122
# In 1d, there's a question of whether we're doing cartesian indexing
3123
# or linear indexing. Support only the former.
3124
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
3125
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
UNCOV
3126
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
UNCOV
3127
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
3128

3129
_sub2ind_recurse(::Any, L, ind) = ind
1,229,352✔
3130
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
149✔
3131
    @inline
1,159✔
3132
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
67,979✔
3133
end
3134
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
842✔
3135
    @inline
21,003,771✔
3136
    r1 = inds[1]
21,068,896✔
3137
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
635,005,378✔
3138
end
3139

3140
nextL(L, l::Integer) = L*l
3,586,461✔
3141
nextL(L, r::AbstractUnitRange) = L*length(r)
318,866,001✔
UNCOV
3142
nextL(L, r::Slice) = L*length(r.indices)
×
3143
offsetin(i, l::Integer) = i-1
9,004,314✔
3144
offsetin(i, r::AbstractUnitRange) = i-first(r)
625,863,115✔
3145

UNCOV
3146
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
3147
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
1✔
3148
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
1,497,388✔
3149
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
3150
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3151
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
63✔
3152

UNCOV
3153
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3154
function _ind2sub_recurse(indslast::NTuple{1}, ind)
3155
    @inline
1,497,389✔
3156
    (_lookup(ind, indslast[1]),)
1,497,389✔
3157
end
3158
function _ind2sub_recurse(inds, ind)
3159
    @inline
1,843,618✔
3160
    r1 = inds[1]
1,843,618✔
3161
    indnext, f, l = _div(ind, r1)
1,843,618✔
3162
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
1,843,618✔
3163
end
3164

3165
_lookup(ind, d::Integer) = ind+1
1✔
3166
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
1,497,388✔
3167
_div(ind, d::Integer) = div(ind, d), 1, d
1✔
3168
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
1,843,617✔
3169

3170
# Vectorized forms
3171
function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
×
UNCOV
3172
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
×
3173
end
3174
_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3175
    _sub2ind_vecs(inds, I1, I...)
3176
_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3177
    _sub2ind_vecs(inds, I1, I...)
3178
function _sub2ind_vecs(inds, I::AbstractVector...)
×
3179
    I1 = I[1]
×
3180
    Iinds = axes1(I1)
×
3181
    for j = 2:length(I)
×
UNCOV
3182
        axes1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(axes1(I[j])))"))
×
UNCOV
3183
    end
×
3184
    Iout = similar(I1)
×
3185
    _sub2ind!(Iout, inds, Iinds, I)
×
3186
    Iout
×
3187
end
3188

3189
function _sub2ind!(Iout, inds, Iinds, I)
×
3190
    @noinline
×
UNCOV
3191
    for i in Iinds
×
3192
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3193
        Iout[i] = sub2ind_vec(inds, i, I)
×
3194
    end
×
3195
    Iout
×
3196
end
3197

3198
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3199
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3200
_sub2ind_vec(i) = ()
×
3201

3202
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3203
    M = length(ind)
×
3204
    t = ntuple(n->similar(ind),Val(N))
×
3205
    for (i,idx) in pairs(IndexLinear(), ind)
×
3206
        sub = _ind2sub(inds, idx)
×
UNCOV
3207
        for j = 1:N
×
UNCOV
3208
            t[j][i] = sub[j]
×
UNCOV
3209
        end
×
UNCOV
3210
    end
×
UNCOV
3211
    t
×
3212
end
3213

3214
## iteration utilities ##
3215

3216
"""
3217
    foreach(f, c...) -> Nothing
3218

3219
Call function `f` on each element of iterable `c`.
3220
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3221
any iterator is finished.
3222

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

3226
# Examples
3227
```jldoctest
3228
julia> tri = 1:3:7; res = Int[];
3229

3230
julia> foreach(x -> push!(res, x^2), tri)
3231

3232
julia> res
3233
3-element Vector{$(Int)}:
3234
  1
3235
 16
3236
 49
3237

3238
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3239
1 with a
3240
4 with b
3241
7 with c
3242
```
3243
"""
3244
foreach(f, itr) = (for x in itr; f(x); end; nothing)
397,749,136✔
3245
foreach(f, itr, itrs...) = (for z in zip(itr, itrs...); f(z...); end; nothing)
1✔
3246

3247
## map over arrays ##
3248

3249
## transform any set of dimensions
3250
## dims specifies which dimensions will be transformed. for example
3251
## dims==1:2 will call f on all slices A[:,:,...]
3252
"""
3253
    mapslices(f, A; dims)
3254

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

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

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

3264
# Examples
3265
```jldoctest
3266
julia> A = reshape(1:30,(2,5,3))
3267
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3268
[:, :, 1] =
3269
 1  3  5  7   9
3270
 2  4  6  8  10
3271

3272
[:, :, 2] =
3273
 11  13  15  17  19
3274
 12  14  16  18  20
3275

3276
[:, :, 3] =
3277
 21  23  25  27  29
3278
 22  24  26  28  30
3279

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

3282
julia> B = mapslices(f, A, dims=(1,2))
3283
1×4×3 Array{$Int, 3}:
3284
[:, :, 1] =
3285
 1  1  1  1
3286

3287
[:, :, 2] =
3288
 11  11  11  11
3289

3290
[:, :, 3] =
3291
 21  21  21  21
3292

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

3295
julia> B == stack(f2, eachslice(A, dims=3))
3296
true
3297

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

3300
julia> mapslices(g, A, dims=[1,3])
3301
1×5×1 Array{Rational{$Int}, 3}:
3302
[:, :, 1] =
3303
 1//21  3//23  1//5  7//27  9//29
3304

3305
julia> map(g, eachslice(A, dims=2))
3306
5-element Vector{Rational{$Int}}:
3307
 1//21
3308
 3//23
3309
 1//5
3310
 7//27
3311
 9//29
3312

3313
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3314
true
3315
```
3316

3317
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3318
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3319
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3320
values in the slice without affecting `A`.
3321
"""
3322
function mapslices(f, A::AbstractArray; dims)
892✔
3323
    isempty(dims) && return map(f, A)
446✔
3324

3325
    for d in dims
566✔
3326
        d isa Integer || throw(ArgumentError("mapslices: dimension must be an integer, got $d"))
881✔
3327
        d >= 1 || throw(ArgumentError("mapslices: dimension must be ≥ 1, got $d"))
882✔
3328
        # Indexing a matrix M[:,1,:] produces a 1-column matrix, but dims=(1,3) here
3329
        # would otherwise ignore 3, and slice M[:,i]. Previously this gave error:
3330
        # BoundsError: attempt to access 2-element Vector{Any} at index [3]
3331
        d > ndims(A) && throw(ArgumentError("mapslices does not accept dimensions > ndims(A) = $(ndims(A)), got $d"))
880✔
3332
    end
884✔
3333
    dim_mask = ntuple(d -> d in dims, ndims(A))
1,988✔
3334

3335
    # Apply the function to the first slice in order to determine the next steps
3336
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3,156✔
3337
    Aslice = A[idx1...]
537✔
3338
    r1 = f(Aslice)
529✔
3339

3340
    res1 = if r1 isa AbstractArray && ndims(r1) > 0
447✔
3341
        n = sum(dim_mask)
29✔
3342
        if ndims(r1) > n && any(ntuple(d -> size(r1,d+n)>1, ndims(r1)-n))
35✔
3343
            s = size(r1)[1:n]
1✔
3344
            throw(DimensionMismatch("mapslices cannot assign slice f(x) of size $(size(r1)) into output of size $s"))
1✔
3345
        end
3346
        r1
28✔
3347
    else
3348
        # If the result of f on a single slice is a scalar then we add singleton
3349
        # dimensions. When adding the dimensions, we have to respect the
3350
        # index type of the input array (e.g. in the case of OffsetArrays)
3351
        _res1 = similar(Aslice, typeof(r1), reduced_indices(Aslice, 1:ndims(Aslice)))
414✔
3352
        _res1[begin] = r1
414✔
3353
        _res1
813✔
3354
    end
3355

3356
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3357
    din = Ref(0)
442✔
3358
    Rsize = ntuple(ndims(A)) do d
451✔
3359
        if d in dims
3,237✔
3360
            axes(res1, din[] += 1)
875✔
3361
        else
3362
            axes(A,d)
805✔
3363
        end
3364
    end
3365
    R = similar(res1, Rsize)
465✔
3366

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

3372
    # That skips the first element, which we already have:
3373
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
2,941✔
3374
    concatenate_setindex!(R, res1, ridx...)
479✔
3375

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

3383
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
468✔
3384
    return R
442✔
3385
end
3386

3387
@noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
442✔
3388
    must_extend = any(dim_mask .& size(R) .> 1)
2,010✔
3389
    if safe_for_reuse
442✔
3390
        # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3391
        # so we can reuse Aslice
3392
        for I in indices
754✔
3393
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
11,173✔
3394
            _unsafe_getindex!(Aslice, A, idx...)
11,173✔
3395
            r = f(Aslice)
16,808✔
3396
            if r isa AbstractArray || must_extend
11,173✔
3397
                ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
65✔
3398
                R[ridx...] = r
130✔
3399
            else
3400
                ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
11,108✔
3401
                R[ridx...] = r
11,108✔
3402
            end
3403
        end
11,173✔
3404
    else
3405
        # we can't guarantee safety (#18524), so allocate new storage for each slice
3406
        for I in indices
130✔
3407
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
1,857✔
3408
            ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
1,857✔
3409
            concatenate_setindex!(R, f(A[idx...]), ridx...)
3,714✔
3410
        end
1,857✔
3411
    end
3412
end
3413

3414
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
1,851✔
3415
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
472✔
3416

3417
## 1 argument
3418

3419
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
2,894✔
3420
    for (i,j) in zip(eachindex(dest),eachindex(A))
629,796,602✔
3421
        val = f(@inbounds A[j])
530,486,121✔
3422
        @inbounds dest[i] = val
385,037,505✔
3423
    end
474,894,190✔
3424
    return dest
334,615,782✔
3425
end
3426

3427
# map on collections
3428
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
133,180✔
3429

3430
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
3,020✔
UNCOV
3431
mapany(f, itr) = Any[f(x) for x in itr]
×
3432

3433
"""
3434
    map(f, c...) -> collection
3435

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

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

3441
# Examples
3442
```jldoctest
3443
julia> map(x -> x * 2, [1, 2, 3])
3444
3-element Vector{Int64}:
3445
 2
3446
 4
3447
 6
3448

3449
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3450
3-element Vector{Int64}:
3451
 11
3452
 22
3453
 33
3454
```
3455
"""
3456
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
443✔
3457

3458
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3459
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3460

3461
## 2 argument
3462
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
304✔
3463
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
595✔
3464
        @inbounds a, b = A[j], B[k]
337,742✔
3465
        val = f(a, b)
337,742✔
3466
        @inbounds dest[i] = val
337,742✔
3467
    end
675,193✔
3468
    return dest
304✔
3469
end
3470

3471
## N argument
3472

3473
@inline ith_all(i, ::Tuple{}) = ()
4,020✔
3474
function ith_all(i, as)
3475
    @_propagate_inbounds_meta
12,060✔
3476
    return (as[1][i], ith_all(i, tail(as))...)
12,060✔
3477
end
3478

3479
function map_n!(f::F, dest::AbstractArray, As) where F
45✔
3480
    idxs1 = LinearIndices(As[1])
45✔
3481
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
360✔
3482
    for i = idxs1
45✔
3483
        @inbounds I = ith_all(i, As)
4,020✔
3484
        val = f(I...)
4,020✔
3485
        @inbounds dest[i] = val
4,020✔
3486
    end
7,995✔
3487
    return dest
45✔
3488
end
3489

3490
"""
3491
    map!(function, destination, collection...)
3492

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

3496
$(_DOCS_ALIASING_WARNING)
3497

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

3500
# Examples
3501
```jldoctest
3502
julia> a = zeros(3);
3503

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

3506
julia> a
3507
3-element Vector{Float64}:
3508
 2.0
3509
 4.0
3510
 6.0
3511

3512
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3513
5-element Vector{$(Int)}:
3514
 101
3515
 103
3516
 105
3517
   0
3518
   0
3519
```
3520
"""
3521
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
43✔
3522
    isempty(As) && throw(ArgumentError(
46✔
3523
        """map! requires at least one "source" argument"""))
3524
    map_n!(f, dest, As)
45✔
3525
end
3526

3527
"""
3528
    map(f, A::AbstractArray...) -> N-array
3529

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

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

3535
# Examples
3536
```
3537
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3538
2×2 Matrix{Rational{$Int}}:
3539
 1//4  2//3
3540
 3//2  4//1
3541

3542
julia> map(+, [1 2; 3 4], zeros(2,1))
3543
ERROR: DimensionMismatch
3544

3545
julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1))  # iterates until 3rd is exhausted
3546
3-element Vector{Float64}:
3547
   2.0
3548
  13.0
3549
 102.0
3550
```
3551
"""
3552
map(f, it, iters...) = collect(Generator(f, it, iters...))
1,255✔
3553

3554
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3555
# (note: must not cause a dispatch loop when 1-item case is not defined)
3556
push!(A, a, b) = push!(push!(A, a), b)
995✔
3557
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
2✔
3558
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
4✔
3559
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
2✔
3560

3561
## hashing AbstractArray ##
3562

3563
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3564
function hash(A::AbstractArray, h::UInt)
16,763✔
3565
    h += hash_abstractarray_seed
16,763✔
3566
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3567
    # Instead hash the tuple of firsts and lasts along each dimension
3568
    h = hash(map(first, axes(A)), h)
17,000✔
3569
    h = hash(map(last, axes(A)), h)
17,000✔
3570

3571
    # For short arrays, it's not worth doing anything complicated
3572
    if length(A) < 8192
17,000✔
3573
        for x in A
21,594✔
3574
            h = hash(x, h)
2,295,376✔
3575
        end
2,111,674✔
3576
        return h
16,759✔
3577
    end
3578

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

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

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

3600
    # Start at the last index
3601
    keyidx = last(ks)
4✔
3602
    linidx = key_to_linear[keyidx]
4✔
3603
    fibskip = prevfibskip = oneunit(linidx)
4✔
3604
    first_linear = first(LinearIndices(linear_to_key))
4✔
3605
    n = 0
4✔
3606
    while true
28,192✔
3607
        n += 1
28,192✔
3608
        # Hash the element
3609
        elt = A[keyidx]
28,192✔
3610
        h = hash(keyidx=>elt, h)
28,192✔
3611

3612
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3613
        linidx = key_to_linear[keyidx]
28,192✔
3614
        linidx < fibskip + first_linear && break
28,192✔
3615
        linidx -= fibskip
28,188✔
3616
        keyidx = linear_to_key[linidx]
28,188✔
3617

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

3628
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3629
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3630
        keyidx === nothing && break
28,188✔
3631
    end
28,188✔
3632

3633
    return h
4✔
3634
end
3635

3636
# The semantics of `collect` are weird. Better to write our own
3637
function rest(a::AbstractArray{T}, state...) where {T}
5✔
3638
    v = Vector{T}(undef, 0)
11✔
3639
    # assume only very few items are taken from the front
3640
    sizehint!(v, length(a))
11✔
3641
    return foldl(push!, Iterators.rest(a, state...), init=v)
11✔
3642
end
3643

3644

3645
## keepat! ##
3646

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

3649
function _keepat!(a::AbstractVector, inds)
7✔
3650
    local prev
11✔
3651
    i = firstindex(a)
11✔
3652
    for k in inds
17✔
3653
        if @isdefined(prev)
34✔
3654
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
27✔
3655
        end
3656
        ak = a[k] # must happen even when i==k for bounds checking
35✔
3657
        if i != k
29✔
3658
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
13✔
3659
        end
3660
        prev = k
29✔
3661
        i = nextind(a, i)
29✔
3662
    end
50✔
3663
    deleteat!(a, i:lastindex(a))
11✔
3664
    return a
6✔
3665
end
3666

3667
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
4✔
3668
    length(m) == length(a) || throw(BoundsError(a, m))
7✔
3669
    j = firstindex(a)
3✔
3670
    for i in eachindex(a, m)
3✔
3671
        @inbounds begin
20✔
3672
            if m[i]
20✔
3673
                i == j || (a[j] = a[i])
20✔
3674
                j = nextind(a, j)
10✔
3675
            end
3676
        end
3677
    end
38✔
3678
    deleteat!(a, j:lastindex(a))
3✔
3679
end
3680

3681
## 1-d circshift ##
3682
function circshift!(a::AbstractVector, shift::Integer)
1,123✔
3683
    n = length(a)
1,141✔
3684
    n == 0 && return a
1,141✔
3685
    shift = mod(shift, n)
2,278✔
3686
    shift == 0 && return a
1,139✔
3687
    l = lastindex(a)
701✔
3688
    reverse!(a, firstindex(a), l-shift)
701✔
3689
    reverse!(a, l-shift+1, lastindex(a))
701✔
3690
    reverse!(a)
701✔
3691
    return a
701✔
3692
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