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

JuliaLang / julia / #37767

02 May 2024 04:02AM UTC coverage: 85.708% (-1.7%) from 87.428%
#37767

push

local

web-flow
Pass CodeGenOpt::Less to LLVM at O1 (rather than CodeGenOpt::None). (#37893)

For context, please see
https://github.com/JuliaLang/julia/pull/35086#issuecomment-700944522.
Regarding alignment with clang, please see
https://reviews.llvm.org/D28409
(/https://github.com/JuliaLang/julia/pull/35086#issuecomment-598282810).

```
Prior to Julia 1.5, Julia passed CodeGenOpt::Aggressive to LLVM at -O1.
As of Julia 1.5, Julia passes CodeGenOpt::None to LLVM at -O1.

This reduction in optimization effort at -O1 improved compilation latency,
but induced appreciable runtime regressions.

This commit makes Julia pass CodeGenOpt::Less to LLVM at -O1,
mitigating the runtime regressions caused by CodeGenOpt::None,
while retaining most of CodeGenOpt::None's latency improvements.

This commit also aligns Julia's CodeGenOpt selection at -O1
with that of clang.
```

Best! :)

74571 of 87006 relevant lines covered (85.71%)

14871255.36 hits per line

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

91.02
/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,286✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
5,744✔
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
1,325,687✔
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}
187✔
76
    @inline
72,357,691✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
72,384,662✔
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,181✔
97
    @inline
644,429,517✔
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)...)
726,923✔
112
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
330,251✔
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,373,463✔
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,693,866✔
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,072✔
166
keys(a::AbstractVector) = LinearIndices(a)
74,235,330✔
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))
28,721,640✔
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,389✔
216
nextind(::AbstractArray, i::Integer) = Int(i)+1
270,767,786✔
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))
33,875,997✔
242
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
32,746,109✔
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))
96,177,337✔
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,243,616✔
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)))
35,758,998✔
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,129,725,073✔
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))
327,846✔
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)))
20,073,181✔
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)))
4,772✔
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)))
38,410,950✔
450
firstindex(a, d) = (@inline; first(axes(a, d)))
2,766✔
451

452
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
405,505✔
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,057✔
472
    x = iterate(itr)
2,102✔
473
    x === nothing && throw(ArgumentError("collection must be non-empty"))
1,102✔
474
    x[1]
1,100✔
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,480✔
506
    v[range(begin, length=min(n, checked_length(v)))]
1,488✔
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]
309,281,166✔
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,369,409✔
607
size_to_strides(s, d) = (s,)
36,352,485✔
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,158✔
680
    @inline
392,974,703✔
681
    checkbounds_indices(Bool, axes(A), I)
407,822,835✔
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)
656✔
688
    @inline
746,540,660✔
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...)
3,253✔
698
    @inline
1,102,733,670✔
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})
3,963✔
724
    @inline
25,242,727✔
725
    return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
953,995,927✔
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,952✔
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))
31,586,912✔
753
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
9,589,415✔
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) =
321,107,045✔
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
2,569✔
765
    b = true
2,569✔
766
    for i in I
13,243✔
767
        b &= checkindex(Bool, inds, i)
6,543,456✔
768
    end
6,545,552✔
769
    b
12,837✔
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)
16,112✔
821
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
12,432✔
822
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
74,633,922✔
823
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
3,428✔
824
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
15,144,115✔
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))
304,521✔
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)
15,089,699✔
834

835
to_shape(::Tuple{}) = ()
18✔
836
to_shape(dims::Dims) = dims
6,886✔
837
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
4,294,408✔
838
# each dimension
839
to_shape(i::Int) = i
33✔
840
to_shape(i::Integer) = Int(i)
128✔
841
to_shape(r::OneTo) = Int(last(r))
23,054✔
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))
971,300,931✔
868
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
971,301,420✔
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)
515✔
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}()
244✔
891
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
64✔
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 multidimensional arrays, they must have
900
equal [`axes`](@ref).
901

902
$(_DOCS_ALIASING_WARNING)
903

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

906
!!! compat "Julia 1.1"
907
    This method requires at least Julia 1.1. In Julia 1.0 this method
908
    is available from the `Future` standard library as `Future.copy!`.
909
"""
910
function copy!(dst::AbstractVector, src::AbstractVector)
20,648,342✔
911
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
96✔
912
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
913
    if length(dst) != length(src)
20,648,434✔
914
        resize!(dst, length(src))
20,421,742✔
915
    end
916
    copyto!(dst, src)
20,648,526✔
917
end
918

919
function copy!(dst::AbstractArray, src::AbstractArray)
920
    axes(dst) == axes(src) || throw(ArgumentError(
16✔
921
        "arrays must have the same axes for copy! (consider using `copyto!`)"))
922
    copyto!(dst, src)
16✔
923
end
924

925
## from general iterable to any array
926

927
# This is `Experimental.@max_methods 1 function copyto! end`, which is not
928
# defined at this point in bootstrap.
929
typeof(function copyto! end).name.max_methods = UInt8(1)
930

931
function copyto!(dest::AbstractArray, src)
10,426,683✔
932
    destiter = eachindex(dest)
10,440,359✔
933
    y = iterate(destiter)
10,440,369✔
934
    for x in src
14,218,476✔
935
        y === nothing &&
5,359,249✔
936
            throw(ArgumentError("destination has fewer elements than required"))
937
        dest[y[1]] = x
5,359,248✔
938
        y = iterate(destiter, y[2])
8,758,133✔
939
    end
8,589,065✔
940
    return dest
10,440,357✔
941
end
942

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

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

989
# this method must be separate from the above since src might not have a length
990
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
580,145✔
991
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
580,145✔
992
        ", elements, but n should be non-negative")))
993
    n == 0 && return dest
580,144✔
994
    dmax = dstart + n - 1
580,139✔
995
    inds = LinearIndices(dest)
580,139✔
996
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
1,160,276✔
997
        sstart < 1 && throw(ArgumentError(LazyString("source start offset (",
4✔
998
            sstart,") is < 1")))
999
        throw(BoundsError(dest, dstart:dmax))
3✔
1000
    end
1001
    y = iterate(src)
580,135✔
1002
    for j = 1:(sstart-1)
633,558✔
1003
        if y === nothing
2,147,483,647✔
1004
            throw(ArgumentError(LazyString(
1✔
1005
                "source has fewer elements than required, ",
1006
                "expected at least ",sstart,", got ",j-1)))
1007
        end
1008
        y = iterate(src, y[2])
2,147,483,647✔
1009
    end
2,147,483,647✔
1010
    i = Int(dstart)
580,134✔
1011
    while i <= dmax && y !== nothing
11,023,017✔
1012
        val, st = y
9,025,173✔
1013
        @inbounds dest[i] = val
10,442,883✔
1014
        y = iterate(src, st)
10,922,719✔
1015
        i += 1
10,442,883✔
1016
    end
10,442,883✔
1017
    i <= dmax && throw(BoundsError(dest, i))
580,134✔
1018
    return dest
580,133✔
1019
end
1020

1021
## copy between abstract arrays - generally more efficient
1022
## since a single index variable can be used.
1023

1024
"""
1025
    copyto!(dest::AbstractArray, src) -> dest
1026

1027
Copy all elements from collection `src` to array `dest`, whose length must be greater than
1028
or equal to the length `n` of `src`. The first `n` elements of `dest` are overwritten,
1029
the other elements are left untouched.
1030

1031
See also [`copy!`](@ref Base.copy!), [`copy`](@ref).
1032

1033
$(_DOCS_ALIASING_WARNING)
1034

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

1039
julia> y = zeros(7);
1040

1041
julia> copyto!(y, x);
1042

1043
julia> y
1044
7-element Vector{Float64}:
1045
 1.0
1046
 0.0
1047
 3.0
1048
 0.0
1049
 5.0
1050
 0.0
1051
 0.0
1052
```
1053
"""
1054
function copyto!(dest::AbstractArray, src::AbstractArray)
2,655,649✔
1055
    isempty(src) && return dest
3,000,754✔
1056
    if dest isa BitArray
2,656,670✔
1057
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1058
        return _copyto_bitarray!(dest, src)
1✔
1059
    end
1060
    src′ = unalias(dest, src)
2,995,840✔
1061
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
3,000,259✔
1062
end
1063

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

1070
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
364,388✔
1071
    isempty(src) && return dest
2,993,600✔
1072
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,993,601✔
1073
    idf, isf = first(destinds), first(srcinds)
2,650,013✔
1074
    Δi = idf - isf
2,650,013✔
1075
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,993,601✔
1076
        throw(BoundsError(dest, srcinds))
1077
    if deststyle isa IndexLinear
2,650,012✔
1078
        if srcstyle isa IndexLinear
2,645,785✔
1079
            # Single-index implementation
1080
            @inbounds for i in srcinds
2,685,480✔
1081
                if isassigned(src, i)
36,762,487✔
1082
                    dest[i + Δi] = src[i]
36,763,574✔
1083
                else
1084
                    _unsetindex!(dest, i + Δi)
17✔
1085
                end
1086
            end
70,839,496✔
1087
        else
1088
            # Dual-index implementation
1089
            i = idf - 1
121,631✔
1090
            @inbounds for a in eachindex(src)
336,712✔
1091
                i += 1
2,704,803✔
1092
                if isassigned(src, a)
2,707,637✔
1093
                    dest[i] = src[a]
2,704,803✔
1094
                else
1095
                    _unsetindex!(dest, i)
×
1096
                end
1097
            end
3,285,080✔
1098
        end
1099
    else
1100
        iterdest, itersrc = eachindex(dest), eachindex(src)
4,227✔
1101
        if iterdest == itersrc
4,227✔
1102
            # Shared-iterator implementation
1103
            @inbounds for I in iterdest
2,493✔
1104
                if isassigned(src, I)
6,089,293✔
1105
                    dest[I] = src[I]
6,089,178✔
1106
                else
1107
                    _unsetindex!(dest, I)
5✔
1108
                end
1109
            end
12,091,353✔
1110
        else
1111
            # Dual-iterator implementation
1112
            ret = iterate(iterdest)
5,932✔
1113
            @inbounds for a in itersrc
2,992✔
1114
                idx, state = ret::NTuple{2,Any}
2,033,814✔
1115
                if isassigned(src, a)
2,033,814✔
1116
                    dest[idx] = src[a]
2,033,814✔
1117
                else
1118
                    _unsetindex!(dest, idx)
×
1119
                end
1120
                ret = iterate(iterdest, state)
2,036,759✔
1121
            end
4,064,659✔
1122
        end
1123
    end
1124
    return dest
2,993,597✔
1125
end
1126

1127
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
72✔
1128
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
22,218✔
1129
end
1130

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

1137
function copyto!(dest::AbstractArray, dstart::Integer,
863,160✔
1138
                 src::AbstractArray, sstart::Integer,
1139
                 n::Integer)
1140
    n == 0 && return dest
863,160✔
1141
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
863,124✔
1142
        n," elements, but n should be non-negative")))
1143
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
863,123✔
1144
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
863,135✔
1145
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
863,114✔
1146
    src′ = unalias(dest, src)
863,108✔
1147
    @inbounds for i = 0:n-1
863,185✔
1148
        if isassigned(src′, sstart+i)
59,393,335✔
1149
            dest[dstart+i] = src′[sstart+i]
59,393,331✔
1150
        else
1151
            _unsetindex!(dest, dstart+i)
×
1152
        end
1153
    end
117,923,554✔
1154
    return dest
863,108✔
1155
end
1156

1157
function copy(a::AbstractArray)
142,413✔
1158
    @_propagate_inbounds_meta
146,785✔
1159
    copymutable(a)
148,856✔
1160
end
1161

1162
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
757✔
1163
                 A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1164
    if length(ir_dest) != length(ir_src)
757✔
1165
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1166
            length(ir_src)," and ",length(ir_dest),")")))
1167
    end
1168
    if length(jr_dest) != length(jr_src)
756✔
1169
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1170
            length(jr_src)," and ",length(jr_dest),")")))
1171
    end
1172
    @boundscheck checkbounds(B, ir_dest, jr_dest)
756✔
1173
    @boundscheck checkbounds(A, ir_src, jr_src)
756✔
1174
    A′ = unalias(B, A)
756✔
1175
    jdest = first(jr_dest)
756✔
1176
    for jsrc in jr_src
1,511✔
1177
        idest = first(ir_dest)
11,508✔
1178
        for isrc in ir_src
23,013✔
1179
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
179,256✔
1180
            idest += step(ir_dest)
179,256✔
1181
        end
347,004✔
1182
        jdest += step(jr_dest)
11,508✔
1183
    end
22,260✔
1184
    return B
756✔
1185
end
1186

1187
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
242,148✔
1188

1189
function copyto_axcheck!(dest, src)
488✔
1190
    _checkaxs(axes(dest), axes(src))
221,314✔
1191
    copyto!(dest, src)
304,955✔
1192
end
1193

1194
"""
1195
    copymutable(a)
1196

1197
Make a mutable copy of an array or iterable `a`.  For `a::Array`,
1198
this is equivalent to `copy(a)`, but for other array types it may
1199
differ depending on the type of `similar(a)`.  For generic iterables
1200
this is equivalent to `collect(a)`.
1201

1202
# Examples
1203
```jldoctest
1204
julia> tup = (1, 2, 3)
1205
(1, 2, 3)
1206

1207
julia> Base.copymutable(tup)
1208
3-element Vector{Int64}:
1209
 1
1210
 2
1211
 3
1212
```
1213
"""
1214
function copymutable(a::AbstractArray)
44✔
1215
    @_propagate_inbounds_meta
149,451✔
1216
    copyto!(similar(a), a)
167,493✔
1217
end
1218
copymutable(itr) = collect(itr)
1✔
1219

1220
zero(x::AbstractArray{T}) where {T<:Number} = fill!(similar(x, typeof(zero(T))), zero(T))
4,429✔
1221
zero(x::AbstractArray{S}) where {S<:Union{Missing, Number}} = fill!(similar(x, typeof(zero(S))), zero(S))
3✔
1222
zero(x::AbstractArray) = map(zero, x)
11✔
1223

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

1238
one(x::AbstractMatrix{T}) where {T} = _one(one(T), x)
139✔
1239
oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
31✔
1240

1241
## iteration support for arrays by iterating over `eachindex` in the array ##
1242
# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1243

1244
# While the definitions for IndexLinear are all simple enough to inline on their
1245
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1246
# inlining.
1247
function iterate(A::AbstractArray, state=(eachindex(A),))
19,620✔
1248
    y = iterate(state...)
139,116,719✔
1249
    y === nothing && return nothing
118,461,950✔
1250
    A[y[1]], (state[1], tail(y)...)
118,111,497✔
1251
end
1252

1253
isempty(a::AbstractArray) = (length(a) == 0)
2,147,483,647✔
1254

1255

1256
## range conversions ##
1257

1258
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
2✔
1259
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
162✔
1260
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
6✔
1261
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
1262
    LinRange(T(r.start), T(r.stop), length(r))
1✔
1263
end
1264

1265
## unsafe/pointer conversions ##
1266

1267
# note: the following type definitions don't mean any AbstractArray is convertible to
1268
# a data Ref. they just map the array element type to the pointer type for
1269
# convenience in cases that work.
1270
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
53,098,845✔
1271
function pointer(x::AbstractArray{T}, i::Integer) where T
39,711✔
1272
    @inline
298,152✔
1273
    pointer(x) + Int(_memory_offset(x, i))::Int
2,900,696✔
1274
end
1275

1276
# The distance from pointer(x) to the element at x[I...] in bytes
1277
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
2,615,720✔
1278
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
28,522✔
1279
    J = _to_subscript_indices(x, I...)
71,463✔
1280
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
276,919✔
1281
end
1282

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

1295
Return a subset of array `A` as selected by the indices `inds`.
1296

1297
Each index may be any [supported index type](@ref man-supported-index-types), such
1298
as an [`Integer`](@ref), [`CartesianIndex`](@ref), [range](@ref Base.AbstractRange), or [array](@ref man-multi-dim-arrays) of supported indices.
1299
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`.
1300

1301
When `inds` selects multiple elements, this function returns a newly
1302
allocated array. To index multiple elements without making a copy,
1303
use [`view`](@ref) instead.
1304

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

1307
# Examples
1308
```jldoctest
1309
julia> A = [1 2; 3 4]
1310
2×2 Matrix{Int64}:
1311
 1  2
1312
 3  4
1313

1314
julia> getindex(A, 1)
1315
1
1316

1317
julia> getindex(A, [2, 1])
1318
2-element Vector{Int64}:
1319
 3
1320
 1
1321

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

1328
julia> getindex(A, 2, 1)
1329
3
1330

1331
julia> getindex(A, CartesianIndex(2, 1))
1332
3
1333

1334
julia> getindex(A, :, 2)
1335
2-element Vector{Int64}:
1336
 2
1337
 4
1338

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

1344
julia> getindex(A, A .> 2)
1345
2-element Vector{Int64}:
1346
 3
1347
 4
1348
```
1349
"""
1350
function getindex(A::AbstractArray, I...)
169,426✔
1351
    @_propagate_inbounds_meta
109,335,909✔
1352
    error_if_canonical_getindex(IndexStyle(A), A, I...)
109,335,909✔
1353
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
215,947,860✔
1354
end
1355
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1356
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
142,948,558✔
1357

1358
@inline unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
387✔
1359

1360
struct CanonicalIndexError <: Exception
1361
    func::String
1362
    type::Any
1363
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
14✔
1364
end
1365

1366
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1367
    throw(CanonicalIndexError("getindex", typeof(A)))
1368
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1369
    throw(CanonicalIndexError("getindex", typeof(A)))
1370
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
×
1371

1372
## Internal definitions
1373
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1374
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1375

1376
## IndexLinear Scalar indexing: canonical method is one Int
1377
_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,386,617✔
1378
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
×
1379
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
342✔
1380
    @inline
2,329,902✔
1381
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
41,068,458✔
1382
    @inbounds r = getindex(A, _to_linear_index(A, I...))
41,068,419✔
1383
    r
2,329,863✔
1384
end
1385
_to_linear_index(A::AbstractArray, i::Integer) = i
6,488✔
1386
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
84,697,278✔
1387
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
289,010✔
1388
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
272,849,005✔
1389

1390
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1391
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
1392
    @inline
283,013✔
1393
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
283,026✔
1394
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
286,203✔
1395
    r
282,998✔
1396
end
1397
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
1398
    @_propagate_inbounds_meta
106,347,156✔
1399
    getindex(A, I...)
130,647,840✔
1400
end
1401
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
274,337✔
1402
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1403
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1404
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
6✔
1405
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1406
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1407
    @inline
80,852✔
1408
    J, Jrem = IteratorsMD.split(I, Val(N))
80,852✔
1409
    _to_subscript_indices(A, J, Jrem)
80,852✔
1410
end
1411
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1412
    __to_subscript_indices(A, axes(A), J, Jrem)
1413
function __to_subscript_indices(A::AbstractArray,
1414
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1415
    @inline
2✔
1416
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1417
end
1418
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
80,850✔
1419
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
25,672✔
1420
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1421
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1422
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1423
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
274,337✔
1424

1425
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1426
# function that allows dispatch on array storage
1427

1428
"""
1429
    setindex!(A, X, inds...)
1430
    A[inds...] = X
1431

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

1435
$(_DOCS_ALIASING_WARNING)
1436

1437
# Examples
1438
```jldoctest
1439
julia> A = zeros(2,2);
1440

1441
julia> setindex!(A, [10, 20], [1, 2]);
1442

1443
julia> A[[3, 4]] = [30, 40];
1444

1445
julia> A
1446
2×2 Matrix{Float64}:
1447
 10.0  30.0
1448
 20.0  40.0
1449
```
1450
"""
1451
function setindex!(A::AbstractArray, v, I...)
1,660✔
1452
    @_propagate_inbounds_meta
2,921,722✔
1453
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,921,722✔
1454
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
7,486,412✔
1455
end
1456
function unsafe_setindex!(A::AbstractArray, v, I...)
1457
    @inline
732✔
1458
    @inbounds r = setindex!(A, v, I...)
732✔
1459
    r
730✔
1460
end
1461

1462
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
7✔
1463
    throw(CanonicalIndexError("setindex!", typeof(A)))
1464
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1465
    throw(CanonicalIndexError("setindex!", typeof(A)))
1466
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
×
1467

1468
## Internal definitions
1469
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1470
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1471

1472
## IndexLinear Scalar indexing
1473
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
4,494,699✔
1474
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
624✔
1475
    @inline
166,944✔
1476
    @boundscheck checkbounds(A, I...)
268,617✔
1477
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
268,588✔
1478
    r
166,923✔
1479
end
1480

1481
# IndexCartesian Scalar indexing
1482
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
1483
    @_propagate_inbounds_meta
2,470,821✔
1484
    setindex!(A, v, I...)
2,470,828✔
1485
end
1486
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
1487
    @inline
23,630✔
1488
    @boundscheck checkbounds(A, I...)
23,635✔
1489
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
23,625✔
1490
    r
23,625✔
1491
end
1492

1493
function _unsetindex!(A::AbstractArray, i::Integer...)
1494
    @_propagate_inbounds_meta
×
1495
    _unsetindex!(A, map(to_index, i)...)
×
1496
end
1497

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

1508
"""
1509
    parent(A)
1510

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

1516
# Examples
1517
```jldoctest
1518
julia> A = [1 2; 3 4]
1519
2×2 Matrix{Int64}:
1520
 1  2
1521
 3  4
1522

1523
julia> V = view(A, 1:2, :)
1524
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1525
 1  2
1526
 3  4
1527

1528
julia> parent(V)
1529
2×2 Matrix{Int64}:
1530
 1  2
1531
 3  4
1532
```
1533
"""
1534
function parent end
1535

1536
parent(a::AbstractArray) = a
1,797✔
1537

1538
## rudimentary aliasing detection ##
1539
"""
1540
    Base.unalias(dest, A)
1541

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

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

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

1552
See also [`Base.mightalias`](@ref).
1553
"""
1554
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
6,621,143✔
1555
unalias(dest, A::AbstractRange) = A
32,491,618✔
1556
unalias(dest, A) = A
3,144,782✔
1557

1558
"""
1559
    Base.unaliascopy(A)
1560

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

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

1581
"""
1582
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1583

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

1586
By default, this simply checks if either of the arrays reference the same memory
1587
regions, as identified by their [`Base.dataids`](@ref).
1588
"""
1589
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B))
6,619,860✔
1590
mightalias(x, y) = false
×
1591

1592
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1593
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1594
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1595
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1596
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
6,413,385✔
1597
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
77,985✔
1598
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1599
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
3,320✔
1600
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
76,649✔
1601

1602
"""
1603
    Base.dataids(A::AbstractArray)
1604

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

1607
Custom arrays that would like to opt-in to aliasing detection of their component
1608
parts can specialize this method to return the concatenation of the `dataids` of
1609
their component parts.  A typical definition for an array that wraps a parent is
1610
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1611
"""
1612
dataids(A::AbstractArray) = (UInt(objectid(A)),)
473,761✔
1613
dataids(A::Memory) = (B = ccall(:jl_genericmemory_owner, Any, (Any,), A); (UInt(pointer(B isa typeof(A) ? B : A)),))
12,464,034✔
1614
dataids(A::Array) = dataids(A.ref.mem)
8,905,847✔
1615
dataids(::AbstractRange) = ()
2,568,757✔
1616
dataids(x) = ()
16,901✔
1617

1618
## get (getindex with a default value) ##
1619

1620
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1621
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1622

1623
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
341✔
1624
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
8✔
1625
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
15✔
1626
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
4✔
1627
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
7✔
1628
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
9✔
1629

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

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

1650
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
2✔
1651
    fill!(X, default)
72✔
1652
    dst, src = indcopy(size(A), I)
2✔
1653
    X[dst...] = A[src...]
2✔
1654
    X
2✔
1655
end
1656

1657
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1658
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1659

1660
## structured matrix methods ##
1661
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
23,943✔
1662
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
33,008✔
1663

1664
## Concatenation ##
1665
eltypeof(x) = typeof(x)
14,701✔
1666
eltypeof(x::AbstractArray) = eltype(x)
14,639✔
1667

1668
promote_eltypeof() = error()
×
1669
promote_eltypeof(v1) = eltypeof(v1)
×
1670
promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2))
1,381✔
1671
promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...))
26,678✔
1672
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
6,870✔
1673
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
20✔
1674

1675
promote_eltype() = error()
×
1676
promote_eltype(v1) = eltype(v1)
×
1677
promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2))
1,780✔
1678
promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...))
507✔
1679
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
178✔
1680
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
1,523✔
1681

1682
#TODO: ERROR CHECK
1683
_cat(catdim::Int) = Vector{Any}()
1✔
1684

1685
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1686
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1687

1688
## cat: special cases
1689
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
316✔
1690
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
235✔
1691
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
97✔
1692
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
8,000,535✔
1693

1694
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
1✔
1695
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
2✔
1696
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
10✔
1697
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
61✔
1698

1699
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
5✔
1700
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
9✔
1701

1702
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1703
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1704
# but that solution currently fails (see #27188 and #27224)
1705
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1706

1707
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
1,499,911✔
1708
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
1,545,433✔
1709
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1710

1711
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
791,065✔
1712
    pos = 1
796,471✔
1713
    for k=1:Int(length(V))::Int
796,471✔
1714
        Vk = V[k]
797,874✔
1715
        p1 = pos + Int(length(Vk))::Int - 1
798,373✔
1716
        a[pos:p1] = Vk
5,805,693✔
1717
        pos = p1+1
797,874✔
1718
    end
799,277✔
1719
    a
796,471✔
1720
end
1721

1722
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
1,030✔
1723

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

1731

1732
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
296✔
1733
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
270✔
1734

1735
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1,036✔
1736
    nargs = length(A)
1,036✔
1737
    nrows = size(A[1], 1)
1,036✔
1738
    ncols = 0
1,036✔
1739
    dense = true
1,036✔
1740
    for j = 1:nargs
1,036✔
1741
        Aj = A[j]
2,124✔
1742
        if size(Aj, 1) != nrows
2,910✔
1743
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1744
        end
1745
        dense &= isa(Aj,Array)
2,123✔
1746
        nd = ndims(Aj)
2,908✔
1747
        ncols += (nd==2 ? size(Aj,2) : 1)
2,604✔
1748
    end
3,211✔
1749
    B = similar(A[1], T, nrows, ncols)
1,616✔
1750
    pos = 1
1,035✔
1751
    if dense
1,035✔
1752
        for k=1:nargs
403✔
1753
            Ak = A[k]
828✔
1754
            n = length(Ak)
1,048✔
1755
            copyto!(B, pos, Ak, 1, n)
1,404✔
1756
            pos += n
828✔
1757
        end
1,253✔
1758
    else
1759
        for k=1:nargs
632✔
1760
            Ak = A[k]
1,294✔
1761
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
1,567✔
1762
            B[:, pos:p1] = Ak
1,696✔
1763
            pos = p1+1
1,294✔
1764
        end
1,820✔
1765
    end
1766
    return B
1,035✔
1767
end
1768

1769
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
65✔
1770
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
202✔
1771

1772
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
489✔
1773
    nargs = length(A)
501✔
1774
    nrows = sum(a->size(a, 1), A)::Int
1,634✔
1775
    ncols = size(A[1], 2)
501✔
1776
    for j = 2:nargs
501✔
1777
        if size(A[j], 2) != ncols
601✔
1778
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1779
        end
1780
    end
676✔
1781
    B = similar(A[1], T, nrows, ncols)
899✔
1782
    pos = 1
500✔
1783
    for k=1:nargs
500✔
1784
        Ak = A[k]
1,082✔
1785
        p1 = pos+size(Ak,1)::Int-1
1,263✔
1786
        B[pos:p1, :] = Ak
1,138✔
1787
        pos = p1+1
1,082✔
1788
    end
1,664✔
1789
    return B
500✔
1790
end
1791

1792
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
1,545,928✔
1793

1794
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1795
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1796

1797
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1798
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1799

1800
## cat: general case
1801

1802
# helper functions
1803
cat_size(A) = (1,)
22,599✔
1804
cat_size(A::AbstractArray) = size(A)
16,320✔
1805
cat_size(A, d) = 1
×
1806
cat_size(A::AbstractArray, d) = size(A, d)
29,736✔
1807

1808
cat_length(::Any) = 1
×
1809
cat_length(a::AbstractArray) = length(a)
472✔
1810

1811
cat_ndims(a) = 0
×
1812
cat_ndims(a::AbstractArray) = ndims(a)
684✔
1813

1814
cat_indices(A, d) = OneTo(1)
22,600✔
1815
cat_indices(A::AbstractArray, d) = axes(A, d)
17,843✔
1816

1817
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,543✔
1818
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1819
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,675✔
1820
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1821
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
853✔
1822
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1823

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

1839
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1840
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1841
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
524✔
1842
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
488✔
1843
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1844
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
2,305✔
1845
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1846
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
1847
    _cs(ndim, shape[1], 1)
23✔
1848
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
19✔
1849
end
1850
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
1851
    next = _cs(ndim, shape[1], nshape[1])
154✔
1852
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
154✔
1853
end
1854
@inline function _cshp(ndim::Int, dims, shape, nshape)
86✔
1855
    a = shape[1]
30,559✔
1856
    b = nshape[1]
30,559✔
1857
    next = dims[1] ? a + b : _cs(ndim, a, b)
31,057✔
1858
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
30,637✔
1859
end
1860

1861
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,076✔
1862
    "mismatch in dimension $d (expected $a got $b)")))
1863

1864
dims2cat(::Val{dims}) where dims = dims2cat(dims)
542✔
1865
function dims2cat(dims)
776✔
1866
    if any(≤(0), dims)
2,952✔
1867
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1868
    end
1869
    ntuple(in(dims), maximum(dims))
1,397✔
1870
end
1871

1872
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
8,249✔
1873

1874
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
7,931✔
1875
    catdims = dims2cat(dims)
9,227✔
1876
    shape = cat_size_shape(catdims, X...)
9,322✔
1877
    A = cat_similar(X[1], T, shape)
10,030✔
1878
    if count(!iszero, catdims)::Int > 1
9,182✔
1879
        fill!(A, zero(T))
791✔
1880
    end
1881
    return __cat(A, shape, catdims, X...)
9,263✔
1882
end
1883
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1884
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1885
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1886

1887
# Why isn't this called `__cat!`?
1888
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
9,775✔
1889

1890
function __cat_offset!(A, shape, catdims, offsets, x, X...)
36,071✔
1891
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1892
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
84,242✔
1893
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
39,007✔
1894
end
1895
__cat_offset!(A, shape, catdims, offsets) = A
9,184✔
1896

1897
function __cat_offset1!(A, shape, catdims, offsets, x)
5✔
1898
    inds = ntuple(length(offsets)) do i
39,189✔
1899
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
42,644✔
1900
    end
1901
    _copy_or_fill!(A, inds, x)
131,332✔
1902
    newoffsets = ntuple(length(offsets)) do i
38,991✔
1903
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
41,346✔
1904
    end
1905
    return newoffsets
38,991✔
1906
end
1907

1908
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
23,552✔
1909
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
107,744✔
1910

1911
"""
1912
    vcat(A...)
1913

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

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

1920
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1921

1922
# Examples
1923
```jldoctest
1924
julia> v = vcat([1,2], [3,4])
1925
4-element Vector{Int64}:
1926
 1
1927
 2
1928
 3
1929
 4
1930

1931
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1932
true
1933

1934
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1935
true
1936

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

1940
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1941
3-element Vector{Float64}:
1942
 1.0
1943
 1.5
1944
 2.0
1945

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

1949
julia> vcat(two...)
1950
3×3 Matrix{Float64}:
1951
 10.0  20.0  30.0
1952
  4.0   5.0   6.0
1953
  7.0   8.0   9.0
1954

1955
julia> vs = [[1, 2], [3, 4], [5, 6]];
1956

1957
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1958
6-element Vector{Int64}:
1959
 1
1960
 2
1961
 3
1962
 4
1963
 5
1964
 6
1965

1966
julia> ans == collect(Iterators.flatten(vs))
1967
true
1968
```
1969
"""
1970
vcat(X...) = cat(X...; dims=Val(1))
434✔
1971
"""
1972
    hcat(A...)
1973

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

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

1981
See also [`vcat`](@ref), [`hvcat`](@ref).
1982

1983
# Examples
1984
```jldoctest
1985
julia> hcat([1,2], [3,4], [5,6])
1986
2×3 Matrix{Int64}:
1987
 1  3  5
1988
 2  4  6
1989

1990
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1991
1×7 Matrix{Int64}:
1992
 1  2  30  40  5  6  7
1993

1994
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1995
true
1996

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

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

2003
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
2004
2×6 Matrix{Float64}:
2005
 0.0  0.0  1.0  2.0  50.0  60.0
2006
 0.0  0.0  3.0  4.0  70.0  80.0
2007

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

2011
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
2012
0×3 Matrix{Int64}
2013

2014
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
2015
2×1 Matrix{Any}:
2016
 1.1
2017
 9.9
2018
```
2019
"""
2020
hcat(X...) = cat(X...; dims=Val(2))
10✔
2021

2022
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
338✔
2023
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
338✔
2024

2025
"""
2026
    cat(A...; dims)
2027

2028
Concatenate the input arrays along the dimensions specified in `dims`.
2029

2030
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
2031
a in A)`.
2032
Along other dimensions, all input arrays should have the same size,
2033
which will also be the size of the output array along those dimensions.
2034

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

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

2044
The keyword also accepts `Val(dims)`.
2045

2046
!!! compat "Julia 1.8"
2047
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
2048

2049
# Examples
2050

2051
Concatenate two arrays in different dimensions:
2052
```jldoctest
2053
julia> a = [1 2 3]
2054
1×3 Matrix{Int64}:
2055
 1  2  3
2056

2057
julia> b = [4 5 6]
2058
1×3 Matrix{Int64}:
2059
 4  5  6
2060

2061
julia> cat(a, b; dims=1)
2062
2×3 Matrix{Int64}:
2063
 1  2  3
2064
 4  5  6
2065

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

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

2076
# Extended Help
2077

2078
Concatenate 3D arrays:
2079
```jldoctest
2080
julia> a = ones(2, 2, 3);
2081

2082
julia> b = ones(2, 2, 4);
2083

2084
julia> c = cat(a, b; dims=3);
2085

2086
julia> size(c) == (2, 2, 7)
2087
true
2088
```
2089

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

2099
Construct a block diagonal matrix:
2100
```
2101
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
2102
4×7 Matrix{Bool}:
2103
 1  0  0  0  0  0  0
2104
 0  1  1  0  0  0  0
2105
 0  1  1  0  0  0  0
2106
 0  0  0  1  1  1  1
2107
```
2108

2109
```
2110
julia> cat(1, [2], [3;;]; dims=Val(2))
2111
1×3 Matrix{Int64}:
2112
 1  2  3
2113
```
2114

2115
!!! note
2116
    `cat` does not join two strings, you may want to use `*`.
2117

2118
```jldoctest
2119
julia> a = "aaa";
2120

2121
julia> b = "bbb";
2122

2123
julia> cat(a, b; dims=1)
2124
2-element Vector{String}:
2125
 "aaa"
2126
 "bbb"
2127

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

2132
julia> a * b
2133
"aaabbb"
2134
```
2135
"""
2136
@inline cat(A...; dims) = _cat(dims, A...)
17,369✔
2137
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
2138
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
216✔
2139

2140
# The specializations for 1 and 2 inputs are important
2141
# especially when running with --inline=no, see #11158
2142
vcat(A::AbstractArray) = cat(A; dims=Val(1))
1✔
2143
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
3✔
2144
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
2145
vcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(1))
7,074✔
2146
hcat(A::AbstractArray) = cat(A; dims=Val(2))
1✔
2147
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
1✔
2148
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
1✔
2149
hcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(2))
6✔
2150

2151
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
2152
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2153
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
2154
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2155
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
2156
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
2157

2158
# 2d horizontal and vertical concatenation
2159

2160
# these are produced in lowering if splatting occurs inside hvcat
2161
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
3✔
2162
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
3✔
2163

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

2173
"""
2174
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2175

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

2181
# Examples
2182
```jldoctest
2183
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2184
(1, 2, 3, 4, 5, 6)
2185

2186
julia> [a b c; d e f]
2187
2×3 Matrix{Int64}:
2188
 1  2  3
2189
 4  5  6
2190

2191
julia> hvcat((3,3), a,b,c,d,e,f)
2192
2×3 Matrix{Int64}:
2193
 1  2  3
2194
 4  5  6
2195

2196
julia> [a b; c d; e f]
2197
3×2 Matrix{Int64}:
2198
 1  2
2199
 3  4
2200
 5  6
2201

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

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

2217
    nc = 0
882✔
2218
    for i=1:rows[1]
882✔
2219
        nc += size(as[i],2)
1,697✔
2220
    end
2,512✔
2221

2222
    nr = 0
882✔
2223
    a = 1
882✔
2224
    for i = 1:nbr
882✔
2225
        nr += size(as[a],1)
1,427✔
2226
        a += rows[i]
1,427✔
2227
    end
1,972✔
2228

2229
    out = similar(as[1], T, nr, nc)
924✔
2230

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

2257
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2258
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2259

2260
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,303✔
2261
    nr = length(rows)
1,303✔
2262
    nc = rows[1]
1,303✔
2263

2264
    a = Matrix{T}(undef, nr, nc)
2,606✔
2265
    if length(a) != length(xs)
1,303✔
2266
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2267
    end
2268
    k = 1
1,301✔
2269
    @inbounds for i=1:nr
1,301✔
2270
        if nc != rows[i]
3,532✔
2271
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2272
        end
2273
        for j=1:nc
3,531✔
2274
            a[i,j] = xs[k]
9,734✔
2275
            k += 1
9,734✔
2276
        end
15,937✔
2277
    end
5,762✔
2278
    a
1,300✔
2279
end
2280

2281
function hvcat_fill!(a::Array, xs::Tuple)
486✔
2282
    nr, nc = size(a,1), size(a,2)
494✔
2283
    len = length(xs)
494✔
2284
    if nr*nc != len
494✔
2285
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2286
    end
2287
    k = 1
493✔
2288
    for i=1:nr
493✔
2289
        @inbounds for j=1:nc
1,320✔
2290
            a[i,j] = xs[k]
8,776✔
2291
            k += 1
8,776✔
2292
        end
16,232✔
2293
    end
2,147✔
2294
    a
493✔
2295
end
2296

2297
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
175✔
2298
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
138✔
2299
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2300
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
3✔
2301

2302
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
346✔
2303
    nr = length(rows)
422✔
2304
    nc = rows[1]
422✔
2305
    for i = 2:nr
422✔
2306
        if nc != rows[i]
816✔
2307
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2308
        end
2309
    end
1,208✔
2310
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
420✔
2311
end
2312

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

2324
## N-dimensional concatenation ##
2325

2326
"""
2327
    hvncat(dim::Int, row_first, values...)
2328
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2329
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2330

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

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

2344
# Examples
2345
```jldoctest
2346
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2347
(1, 2, 3, 4, 5, 6)
2348

2349
julia> [a b c;;; d e f]
2350
1×3×2 Array{Int64, 3}:
2351
[:, :, 1] =
2352
 1  2  3
2353

2354
[:, :, 2] =
2355
 4  5  6
2356

2357
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2358
2×1×3 Array{Int64, 3}:
2359
[:, :, 1] =
2360
 1
2361
 2
2362

2363
[:, :, 2] =
2364
 3
2365
 4
2366

2367
[:, :, 3] =
2368
 5
2369
 6
2370

2371
julia> [a b;;; c d;;; e f]
2372
1×2×3 Array{Int64, 3}:
2373
[:, :, 1] =
2374
 1  2
2375

2376
[:, :, 2] =
2377
 3  4
2378

2379
[:, :, 3] =
2380
 5  6
2381

2382
julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2383
1×3×2 Array{Int64, 3}:
2384
[:, :, 1] =
2385
 1  2  3
2386

2387
[:, :, 2] =
2388
 4  5  6
2389
```
2390

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

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

2414
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
28✔
2415
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
91✔
2416
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
89✔
2417
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2418
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2419
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
132✔
2420

2421

2422
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2423
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2424

2425
# 1-dimensional hvncat methods
2426

2427
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
4✔
2428
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2429
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
4✔
2430
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
4✔
2431
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2432
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
4✔
2433
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2434

2435
_typed_hvncat_0d_only_one() =
8✔
2436
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2437

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

2441
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
15✔
2442
    N < 0 &&
15✔
2443
        throw(ArgumentError("concatenation dimension must be non-negative"))
2444
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
14✔
2445
end
2446

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

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

2468
    nd = N
17✔
2469

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

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

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

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

2508
    k = 1
4✔
2509
    for a ∈ as
4✔
2510
        if a isa AbstractArray
12✔
2511
            lena = length(a)
2✔
2512
            copyto!(A, k, a, 1, lena)
2✔
2513
            k += lena
2✔
2514
        else
2515
            A[k] = a
10✔
2516
            k += 1
10✔
2517
        end
2518
    end
16✔
2519
    return A
4✔
2520
end
2521

2522
# 0-dimensional cases for balanced and unbalanced hvncat method
2523

2524
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2525
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2526

2527

2528
# balanced dimensions hvncat methods
2529

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

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

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

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

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

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

2600
    d1 = row_first ? 2 : 1
58✔
2601
    d2 = row_first ? 1 : 2
58✔
2602

2603
    outdims = zeros(Int, N)
203✔
2604

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

2626
    # discover number of rows or columns
2627
    for i ∈ 1:dims[d1]
52✔
2628
        outdims[d1] += cat_size(as[i], d1)
108✔
2629
    end
164✔
2630

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

2665
    outlen = prod(outdims)
72✔
2666
    elementcount == outlen ||
36✔
2667
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2668

2669
    # copy into final array
2670
    A = cat_similar(as[1], T, outdims)
36✔
2671
    # @assert all(==(0), currentdims)
2672
    outdims .= 0
108✔
2673
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
36✔
2674
    return A
36✔
2675
end
2676

2677

2678
# unbalanced dimensions hvncat methods
2679

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

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

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

2698
    d1 = row_first ? 2 : 1
67✔
2699
    d2 = row_first ? 1 : 2
67✔
2700

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

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

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

2732
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
899✔
2733

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

2752
    outlen = prod(outdims)
30✔
2753
    elementcount == outlen ||
15✔
2754
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2755

2756
    if row_first
15✔
2757
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2758
    end
2759

2760
    # @assert all(==(0), currentdims)
2761
    # @assert all(==(0), blockcounts)
2762

2763
    # copy into final array
2764
    A = cat_similar(as[1], T, outdims)
15✔
2765
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
15✔
2766
    return A
15✔
2767
end
2768

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

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

2798
        @inbounds for j ∈ (d1, d2, 3:N...)
270✔
2799
            offsets[j] += cat_size(a, j)
518✔
2800
            offsets[j] < outdims[j] && break
518✔
2801
            offsets[j] = 0
304✔
2802
        end
304✔
2803
    end
270✔
2804
end
2805

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

2819
"""
2820
    stack(iter; [dims])
2821

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

2825
By default the axes of the elements are placed first,
2826
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2827
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2828

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

2833
The various [`cat`](@ref) functions also combine arrays. However, these all
2834
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2835
the arrays along new dimensions.
2836
They also accept arrays as separate arguments, rather than a single collection.
2837

2838
!!! compat "Julia 1.9"
2839
    This function requires at least Julia 1.9.
2840

2841
# Examples
2842
```jldoctest
2843
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2844

2845
julia> mat = stack(vecs)
2846
2×3 Matrix{Float32}:
2847
 1.0  30.0  500.0
2848
 2.0  40.0  600.0
2849

2850
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2851
true
2852

2853
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2854
true
2855

2856
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2857
2×4 Matrix{Int64}:
2858
  1   2   3   4
2859
 10  11  12  13
2860

2861
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2862
true
2863

2864
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2865
3×2 Matrix{Float32}:
2866
   1.0    2.0
2867
  30.0   40.0
2868
 500.0  600.0
2869

2870
julia> x = rand(3,4);
2871

2872
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2873
true
2874
```
2875

2876
Higher-dimensional examples:
2877

2878
```jldoctest
2879
julia> A = rand(5, 7, 11);
2880

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

2883
julia> (element = size(first(E)), container = size(E))
2884
(element = (5, 11), container = (7,))
2885

2886
julia> stack(E) |> size
2887
(5, 11, 7)
2888

2889
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2890
true
2891

2892
julia> A == stack(E; dims=2)
2893
true
2894

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

2897
julia> (element = size(first(M)), container = size(M))
2898
(element = (2, 3), container = (5, 7))
2899

2900
julia> stack(M) |> size  # keeps all dimensions
2901
(2, 3, 5, 7)
2902

2903
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2904
(35, 2, 3)
2905

2906
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2907
(14, 15)
2908
```
2909
"""
2910
stack(iter; dims=:) = _stack(dims, iter)
254✔
2911

2912
"""
2913
    stack(f, args...; [dims])
2914

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

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

2922
See also [`mapslices`](@ref), [`eachcol`](@ref).
2923

2924
# Examples
2925
```jldoctest
2926
julia> stack(c -> (c, c-32), "julia")
2927
2×5 Matrix{Char}:
2928
 'j'  'u'  'l'  'i'  'a'
2929
 'J'  'U'  'L'  'I'  'A'
2930

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

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

2944
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2945

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

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

2977
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2978
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2979
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2980

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

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

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

3006
    newaxis = _vec_axis(A)
21✔
3007
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
122✔
3008
    B = similar(_ensure_array(x1), T, outax...)
41✔
3009

3010
    if dims == 1
21✔
3011
        _dim_stack!(Val(1), B, x1, xrest)
13✔
3012
    elseif dims == 2
8✔
3013
        _dim_stack!(Val(2), B, x1, xrest)
4✔
3014
    else
3015
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
3016
    end
3017
    B
18✔
3018
end
3019

3020
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
3021
    before = ntuple(d -> Colon(), dims - 1)
29✔
3022
    after = ntuple(d -> Colon(), ndims(B) - dims)
42✔
3023

3024
    i = firstindex(B, dims)
21✔
3025
    copyto!(view(B, before..., i, after...), x1)
40✔
3026

3027
    for x in xrest
29✔
3028
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
3029
        i += 1
3,261✔
3030
        @inbounds copyto!(view(B, before..., i, after...), x)
6,415✔
3031
    end
3,261✔
3032
end
3033

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

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

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

3048

3049
## Reductions and accumulates ##
3050

3051
function isequal(A::AbstractArray, B::AbstractArray)
246,647✔
3052
    if A === B return true end
289,102✔
3053
    if axes(A) != axes(B)
574,672✔
3054
        return false
2,924✔
3055
    end
3056
    for (a, b) in zip(A, B)
571,169✔
3057
        if !isequal(a, b)
92,100,315✔
3058
            return false
624✔
3059
        end
3060
    end
183,750,780✔
3061
    return true
285,259✔
3062
end
3063

3064
function cmp(A::AbstractVector, B::AbstractVector)
45✔
3065
    for (a, b) in zip(A, B)
684✔
3066
        if !isequal(a, b)
751✔
3067
            return isless(a, b) ? -1 : 1
462✔
3068
        end
3069
    end
833✔
3070
    return cmp(length(A), length(B))
15✔
3071
end
3072

3073
"""
3074
    isless(A::AbstractVector, B::AbstractVector)
3075

3076
Return `true` when `A` is less than `B` in lexicographic order.
3077
"""
3078
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
442✔
3079

3080
function (==)(A::AbstractArray, B::AbstractArray)
6,552,583✔
3081
    if axes(A) != axes(B)
13,147,504✔
3082
        return false
3,581✔
3083
    end
3084
    anymissing = false
6,563,391✔
3085
    for (a, b) in zip(A, B)
12,257,053✔
3086
        eq = (a == b)
321,368,360✔
3087
        if ismissing(eq)
286,761,173✔
3088
            anymissing = true
24✔
3089
        elseif !eq
320,478,807✔
3090
            return false
2,839✔
3091
        end
3092
    end
635,269,722✔
3093
    return anymissing ? missing : true
6,569,163✔
3094
end
3095

3096
# _sub2ind and _ind2sub
3097
# fallbacks
3098
function _sub2ind(A::AbstractArray, I...)
263✔
3099
    @inline
257,787,907✔
3100
    _sub2ind(axes(A), I...)
272,849,005✔
3101
end
3102

3103
function _ind2sub(A::AbstractArray, ind)
3104
    @inline
274,338✔
3105
    _ind2sub(axes(A), ind)
274,338✔
3106
end
3107

3108
# 0-dimensional arrays and indexing with []
3109
_sub2ind(::Tuple{}) = 1
×
3110
_sub2ind(::DimsInteger) = 1
×
3111
_sub2ind(::Indices) = 1
×
3112
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
4✔
3113

3114
# Generic cases
3115
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
3,329,222✔
3116
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
272,966,908✔
3117
# In 1d, there's a question of whether we're doing cartesian indexing
3118
# or linear indexing. Support only the former.
3119
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
3120
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3121
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
3122
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
3123

3124
_sub2ind_recurse(::Any, L, ind) = ind
89,174✔
3125
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
147✔
3126
    @inline
1,159✔
3127
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
68,071✔
3128
end
3129
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
842✔
3130
    @inline
13,350,483✔
3131
    r1 = inds[1]
13,415,608✔
3132
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
559,142,654✔
3133
end
3134

3135
nextL(L, l::Integer) = L*l
1,614,791✔
3136
nextL(L, r::AbstractUnitRange) = L*length(r)
281,233,486✔
3137
nextL(L, r::Slice) = L*length(r.indices)
×
3138
offsetin(i, l::Integer) = i-1
4,878,776✔
3139
offsetin(i, r::AbstractUnitRange) = i-first(r)
554,125,929✔
3140

3141
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
3142
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
1✔
3143
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
274,362✔
3144
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
3145
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3146
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
36✔
3147

3148
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3149
function _ind2sub_recurse(indslast::NTuple{1}, ind)
3150
    @inline
274,363✔
3151
    (_lookup(ind, indslast[1]),)
274,363✔
3152
end
3153
function _ind2sub_recurse(inds, ind)
3154
    @inline
436,245✔
3155
    r1 = inds[1]
436,245✔
3156
    indnext, f, l = _div(ind, r1)
436,245✔
3157
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
436,245✔
3158
end
3159

3160
_lookup(ind, d::Integer) = ind+1
1✔
3161
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
274,362✔
3162
_div(ind, d::Integer) = div(ind, d), 1, d
1✔
3163
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
436,244✔
3164

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

3184
function _sub2ind!(Iout, inds, Iinds, I)
×
3185
    @noinline
×
3186
    for i in Iinds
×
3187
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3188
        Iout[i] = sub2ind_vec(inds, i, I)
×
3189
    end
×
3190
    Iout
×
3191
end
3192

3193
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3194
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3195
_sub2ind_vec(i) = ()
×
3196

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

3209
## iteration utilities ##
3210

3211
"""
3212
    foreach(f, c...) -> Nothing
3213

3214
Call function `f` on each element of iterable `c`.
3215
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3216
any iterator is finished.
3217

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

3221
# Examples
3222
```jldoctest
3223
julia> tri = 1:3:7; res = Int[];
3224

3225
julia> foreach(x -> push!(res, x^2), tri)
3226

3227
julia> res
3228
3-element Vector{$(Int)}:
3229
  1
3230
 16
3231
 49
3232

3233
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3234
1 with a
3235
4 with b
3236
7 with c
3237
```
3238
"""
3239
foreach(f, itr) = (for x in itr; f(x); end; nothing)
355,361,090✔
3240
foreach(f, itr, itrs...) = (for z in zip(itr, itrs...); f(z...); end; nothing)
1✔
3241

3242
## map over arrays ##
3243

3244
## transform any set of dimensions
3245
## dims specifies which dimensions will be transformed. for example
3246
## dims==1:2 will call f on all slices A[:,:,...]
3247
"""
3248
    mapslices(f, A; dims)
3249

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

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

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

3259
# Examples
3260
```jldoctest
3261
julia> A = reshape(1:30,(2,5,3))
3262
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3263
[:, :, 1] =
3264
 1  3  5  7   9
3265
 2  4  6  8  10
3266

3267
[:, :, 2] =
3268
 11  13  15  17  19
3269
 12  14  16  18  20
3270

3271
[:, :, 3] =
3272
 21  23  25  27  29
3273
 22  24  26  28  30
3274

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

3277
julia> B = mapslices(f, A, dims=(1,2))
3278
1×4×3 Array{$Int, 3}:
3279
[:, :, 1] =
3280
 1  1  1  1
3281

3282
[:, :, 2] =
3283
 11  11  11  11
3284

3285
[:, :, 3] =
3286
 21  21  21  21
3287

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

3290
julia> B == stack(f2, eachslice(A, dims=3))
3291
true
3292

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

3295
julia> mapslices(g, A, dims=[1,3])
3296
1×5×1 Array{Rational{$Int}, 3}:
3297
[:, :, 1] =
3298
 1//21  3//23  1//5  7//27  9//29
3299

3300
julia> map(g, eachslice(A, dims=2))
3301
5-element Vector{Rational{$Int}}:
3302
 1//21
3303
 3//23
3304
 1//5
3305
 7//27
3306
 9//29
3307

3308
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3309
true
3310
```
3311

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

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

3330
    # Apply the function to the first slice in order to determine the next steps
3331
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3,156✔
3332
    Aslice = A[idx1...]
537✔
3333
    r1 = f(Aslice)
529✔
3334

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

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

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

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

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

3378
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
468✔
3379
    return R
442✔
3380
end
3381

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

3409
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
1,851✔
3410
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
472✔
3411

3412
## 1 argument
3413

3414
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
2,834✔
3415
    for (i,j) in zip(eachindex(dest),eachindex(A))
525,917,506✔
3416
        val = f(@inbounds A[j])
442,278,791✔
3417
        @inbounds dest[i] = val
320,841,820✔
3418
    end
395,688,927✔
3419
    return dest
279,922,793✔
3420
end
3421

3422
# map on collections
3423
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
189,014✔
3424

3425
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
3,299✔
3426
mapany(f, itr) = Any[f(x) for x in itr]
×
3427

3428
"""
3429
    map(f, c...) -> collection
3430

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

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

3436
# Examples
3437
```jldoctest
3438
julia> map(x -> x * 2, [1, 2, 3])
3439
3-element Vector{Int64}:
3440
 2
3441
 4
3442
 6
3443

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

3453
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3454
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3455

3456
## 2 argument
3457
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
304✔
3458
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
679✔
3459
        @inbounds a, b = A[j], B[k]
338,102✔
3460
        val = f(a, b)
338,102✔
3461
        @inbounds dest[i] = val
338,102✔
3462
    end
675,871✔
3463
    return dest
346✔
3464
end
3465

3466
## N argument
3467

3468
@inline ith_all(i, ::Tuple{}) = ()
4,020✔
3469
function ith_all(i, as)
3470
    @_propagate_inbounds_meta
12,060✔
3471
    return (as[1][i], ith_all(i, tail(as))...)
12,060✔
3472
end
3473

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

3485
"""
3486
    map!(function, destination, collection...)
3487

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

3491
$(_DOCS_ALIASING_WARNING)
3492

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

3495
# Examples
3496
```jldoctest
3497
julia> a = zeros(3);
3498

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

3501
julia> a
3502
3-element Vector{Float64}:
3503
 2.0
3504
 4.0
3505
 6.0
3506

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

3522
"""
3523
    map(f, A::AbstractArray...) -> N-array
3524

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

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

3530
# Examples
3531
```
3532
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3533
2×2 Matrix{Rational{$Int}}:
3534
 1//4  2//3
3535
 3//2  4//1
3536

3537
julia> map(+, [1 2; 3 4], zeros(2,1))
3538
ERROR: DimensionMismatch
3539

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

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

3556
## hashing AbstractArray ##
3557

3558
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3559
function hash(A::AbstractArray, h::UInt)
16,905✔
3560
    h += hash_abstractarray_seed
16,905✔
3561
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3562
    # Instead hash the tuple of firsts and lasts along each dimension
3563
    h = hash(map(first, axes(A)), h)
17,142✔
3564
    h = hash(map(last, axes(A)), h)
17,142✔
3565

3566
    # For short arrays, it's not worth doing anything complicated
3567
    if length(A) < 8192
17,142✔
3568
        for x in A
21,732✔
3569
            h = hash(x, h)
2,291,599✔
3570
        end
2,107,330✔
3571
        return h
16,901✔
3572
    end
3573

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

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

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

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

3607
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3608
        linidx = key_to_linear[keyidx]
28,192✔
3609
        linidx < fibskip + first_linear && break
28,192✔
3610
        linidx -= fibskip
28,188✔
3611
        keyidx = linear_to_key[linidx]
28,188✔
3612

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

3623
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3624
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3625
        keyidx === nothing && break
28,188✔
3626
    end
28,188✔
3627

3628
    return h
4✔
3629
end
3630

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

3639

3640
## keepat! ##
3641

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

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

3662
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
4✔
3663
    length(m) == length(a) || throw(BoundsError(a, m))
7✔
3664
    j = firstindex(a)
3✔
3665
    for i in eachindex(a, m)
3✔
3666
        @inbounds begin
20✔
3667
            if m[i]
20✔
3668
                i == j || (a[j] = a[i])
17✔
3669
                j = nextind(a, j)
9✔
3670
            end
3671
        end
3672
    end
38✔
3673
    deleteat!(a, j:lastindex(a))
3✔
3674
end
3675

3676
## 1-d circshift ##
3677
function circshift!(a::AbstractVector, shift::Integer)
1,123✔
3678
    n = length(a)
1,141✔
3679
    n == 0 && return a
1,141✔
3680
    shift = mod(shift, n)
2,278✔
3681
    shift == 0 && return a
1,139✔
3682
    l = lastindex(a)
851✔
3683
    reverse!(a, firstindex(a), l-shift)
851✔
3684
    reverse!(a, l-shift+1, lastindex(a))
851✔
3685
    reverse!(a)
851✔
3686
    return a
851✔
3687
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