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

JuliaLang / julia / #37632

26 Sep 2023 06:44AM UTC coverage: 86.999% (-0.9%) from 87.914%
#37632

push

local

web-flow
inference: make `throw` block deoptimization concrete-eval friendly (#49235)

The deoptimization can sometimes destroy the effects analysis and
disable [semi-]concrete evaluation that is otherwise possible. This is
because the deoptimization was designed with the type domain
profitability in mind (#35982), and hasn't been adequately considering
the effects domain.

This commit makes the deoptimization aware of the effects domain more
and enables the `throw` block deoptimization only when the effects
already known to be ineligible for concrete-evaluation.

In our current effect system, `ALWAYS_FALSE`/`false` means that the
effect can not be refined to `ALWAYS_TRUE`/`true` anymore (unless given
user annotation later). Therefore we can enable the `throw` block
deoptimization without hindering the chance of concrete-evaluation when
any of the following conditions are met:
- `effects.consistent === ALWAYS_FALSE`
- `effects.effect_free === ALWAYS_FALSE`
- `effects.terminates === false`
- `effects.nonoverlayed === false`

Here are some numbers:

| Metric | master | this commit | #35982 reverted (set
`unoptimize_throw_blocks=false`) |

|-------------------------|-----------|-------------|--------------------------------------------|
| Base (seconds) | 15.579300 | 15.206645 | 15.296319 |
| Stdlibs (seconds) | 17.919013 | 17.667094 | 17.738128 |
| Total (seconds) | 33.499279 | 32.874737 | 33.035448 |
| Precompilation (seconds) | 49.967516 | 49.421121 | 49.999998 |
| First time `plot(rand(10,3))` [^1] | `2.476678 seconds (11.74 M
allocations)` | `2.430355 seconds (11.77 M allocations)` | `2.514874
seconds (11.64 M allocations)` |
| First time `solve(prob, QNDF())(5.0)` [^2] | `4.469492 seconds (15.32
M allocations)` | `4.499217 seconds (15.41 M allocations)` | `4.470772
seconds (15.38 M allocations)` |

[^1]: With disabling precompilation of Plots.jl.
[^2]: With disabling precompilation of OrdinaryDiffEq.

These numbers ma... (continued)

7 of 7 new or added lines in 1 file covered. (100.0%)

73407 of 84377 relevant lines covered (87.0%)

11275130.05 hits per line

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

92.17
/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
51,610✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
2,579✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
4,450✔
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,309,415✔
43

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

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

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

51
# Examples
52

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

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

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

63
# Usage note
64

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

69
```julia
70
ix = axes(v, 1)
71
ix[2:end]          # will work for eg Vector, but may fail in general
72
ix[(begin+1):end]  # works for generalized indexes
73
```
74
"""
75
function axes(A::AbstractArray{T,N}, d) where {T,N}
66,307,961✔
76
    @inline
66,307,741✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
66,313,368✔
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)
235,295,355✔
97
    @inline
100,054,211✔
98
    map(unchecked_oneto, size(A))
2,147,483,647✔
99
end
100

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

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

108
See also [`require_one_based_indexing`](@ref).
109
"""
110
has_offset_axes(A) = _any_tuple(x->Int(first(x))::Int != 1, false, axes(A)...)
513,608✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
117,243✔
112
# Use `_any_tuple` to avoid unneeded invoke.
113
# note: this could call `any` directly if the compiler can infer it
114
has_offset_axes(As...) = _any_tuple(has_offset_axes, false, As...)
319,745✔
115
has_offset_axes(::Colon) = false
1,094✔
116
has_offset_axes(::Array) = false
558,435✔
117

118
"""
119
    require_one_based_indexing(A::AbstractArray)
120
    require_one_based_indexing(A,B...)
121

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

125
!!! compat "Julia 1.2"
126
     This function requires at least Julia 1.2.
127
"""
128
require_one_based_indexing(A...) = !has_offset_axes(A...) || throw(ArgumentError("offset arrays are not supported but got an array with index other than 1"))
1,312,339✔
129

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

212
prevind(::AbstractArray, i::Integer) = Int(i)-1
146,593✔
213
nextind(::AbstractArray, i::Integer) = Int(i)+1
261,569,522✔
214

215

216
"""
217
    eltype(type)
218

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

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

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

232
julia> eltype(fill(0x1, (2,2)))
233
UInt8
234
```
235
"""
236
eltype(::Type) = Any
14,080✔
237
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
3✔
238
eltype(x) = eltype(typeof(x))
5,226,264✔
239
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
3,192,643✔
240

241
"""
242
    elsize(type)
243

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

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

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

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

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

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

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

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

278
Return the number of elements in the collection.
279

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

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

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

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

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

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

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

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

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

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

317
# eachindex iterates over all indices. IndexCartesian definitions are later.
318
eachindex(A::AbstractVector) = (@inline(); axes1(A))
1,132,562,239✔
319

320

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

449
first(a::AbstractArray) = a[first(eachindex(a))]
395,229✔
450

451
"""
452
    first(coll)
453

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

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

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

464
julia> first([1; 2; 3; 4])
465
1
466
```
467
"""
468
function first(itr)
3,391,948✔
469
    x = iterate(itr)
6,765,608✔
470
    x === nothing && throw(ArgumentError("collection must be non-empty"))
3,391,949✔
471
    x[1]
3,391,947✔
472
end
473

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

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

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

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

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

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

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

506
"""
507
    last(coll)
508

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

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

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

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

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

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

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

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

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

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

556
"""
557
    strides(A)
558

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

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

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

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

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

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

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

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

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

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

603
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
297,225✔
604
size_to_strides(s, d) = (s,)
691,176✔
605
size_to_strides(s) = ()
×
606

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

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

633
## Bounds checking ##
634

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

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

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

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

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

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

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

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

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

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

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

695
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
696
"""
697
function checkbounds(A::AbstractArray, I...)
914,446,701✔
698
    @inline
254,820,952✔
699
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
914,506,063✔
700
    nothing
914,503,369✔
701
end
702

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

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

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

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

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

721
See also [`checkbounds`](@ref).
722
"""
723
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
312,953,574✔
724
    @inline
145,927,733✔
725
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
313,201,477✔
726
end
727
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
14,373✔
728
    @inline
3,667✔
729
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
27,026✔
730
end
731
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
577,847✔
732
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
×
733

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

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

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

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

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

752
julia> checkindex(Bool, 1:20, 21)
753
false
754
```
755
"""
756
checkindex(::Type{Bool}, inds::AbstractUnitRange, i) =
×
757
    throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
758
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
6,100,530✔
759
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
3,049,762✔
760
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
2,147,483,647✔
761
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
229✔
762
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
79,678✔
763
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
9,477,904✔
764
    @_propagate_inbounds_meta
1,515,998✔
765
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
391,821,505✔
766
end
767
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == axes1(I)
2✔
768
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool}) = false
1✔
769
function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
6,028✔
770
    @inline
630✔
771
    b = true
630✔
772
    for i in I
8,333✔
773
        b &= checkindex(Bool, inds, i)
6,272,447✔
774
    end
6,303,249✔
775
    b
7,809✔
776
end
777

778
# See also specializations in multidimensional
779

780
## Constructors ##
781

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

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

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

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

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

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

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

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

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

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

841
to_shape(::Tuple{}) = ()
18✔
842
to_shape(dims::Dims) = dims
6,198✔
843
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
6,826,884✔
844
# each dimension
845
to_shape(i::Int) = i
33✔
846
to_shape(i::Integer) = Int(i)
41✔
847
to_shape(r::OneTo) = Int(last(r))
323,481✔
848
to_shape(r::AbstractUnitRange) = r
188✔
849

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

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

857
**Examples**:
858

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

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

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

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

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

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

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

883
# Examples
884

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

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

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

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

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

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

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

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

929
## from general iterable to any array
930

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

935
function copyto!(dest::AbstractArray, src)
3,650,031✔
936
    destiter = eachindex(dest)
3,661,015✔
937
    y = iterate(destiter)
4,834,244✔
938
    for x in src
5,955,665✔
939
        y === nothing &&
3,951,567✔
940
            throw(ArgumentError("destination has fewer elements than required"))
941
        dest[y[1]] = x
3,951,686✔
942
        y = iterate(destiter, y[2])
6,729,684✔
943
    end
6,364,381✔
944
    return dest
3,661,013✔
945
end
946

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

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

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

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

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

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

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

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

1041
julia> y = zeros(7);
1042

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

1045
julia> y
1046
7-element Vector{Float64}:
1047
 1.0
1048
 0.0
1049
 3.0
1050
 0.0
1051
 5.0
1052
 0.0
1053
 0.0
1054
```
1055
"""
1056
function copyto!(dest::AbstractArray, src::AbstractArray)
2,739,149✔
1057
    isempty(src) && return dest
2,904,034✔
1058
    if dest isa BitArray
2,738,756✔
1059
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1060
        return _copyto_bitarray!(dest, src)
1✔
1061
    end
1062
    src′ = unalias(dest, src)
2,918,528✔
1063
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,903,640✔
1064
end
1065

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

1072
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
2,900,917✔
1073
    isempty(src) && return dest
2,903,640✔
1074
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,903,641✔
1075
    idf, isf = first(destinds), first(srcinds)
2,738,598✔
1076
    Δi = idf - isf
2,738,598✔
1077
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,903,641✔
1078
        throw(BoundsError(dest, srcinds))
1079
    if deststyle isa IndexLinear
2,738,597✔
1080
        if srcstyle isa IndexLinear
2,735,322✔
1081
            # Single-index implementation
1082
            @inbounds for i in srcinds
5,272,852✔
1083
                dest[i + Δi] = src[i]
35,627,996✔
1084
            end
68,609,609✔
1085
        else
1086
            # Dual-index implementation
1087
            i = idf - 1
102,140✔
1088
            @inbounds for a in src
527,831✔
1089
                dest[i+=1] = a
1,949,261✔
1090
            end
3,627,215✔
1091
        end
1092
    else
1093
        iterdest, itersrc = eachindex(dest), eachindex(src)
3,275✔
1094
        if iterdest == itersrc
3,275✔
1095
            # Shared-iterator implementation
1096
            for I in iterdest
672✔
1097
                @inbounds dest[I] = src[I]
6,015,389✔
1098
            end
12,016,997✔
1099
        else
1100
            # Dual-iterator implementation
1101
            ret = iterate(iterdest)
5,878✔
1102
            @inbounds for a in src
4,984✔
1103
                idx, state = ret::NTuple{2,Any}
2,033,771✔
1104
                dest[idx] = a
2,033,771✔
1105
                ret = iterate(iterdest, state)
2,036,711✔
1106
            end
4,032,997✔
1107
        end
1108
    end
1109
    return dest
2,903,639✔
1110
end
1111

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

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

1122
function copyto!(dest::AbstractArray, dstart::Integer,
414,935✔
1123
               src::AbstractArray, sstart::Integer,
1124
               n::Integer)
1125
    n == 0 && return dest
414,935✔
1126
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
414,933✔
1127
        n," elements, but n should be non-negative")))
1128
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
414,932✔
1129
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
414,944✔
1130
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
414,923✔
1131
    src′ = unalias(dest, src)
414,962✔
1132
    @inbounds for i = 0:n-1
829,834✔
1133
        dest[dstart+i] = src′[sstart+i]
20,966,105✔
1134
    end
41,517,293✔
1135
    return dest
414,917✔
1136
end
1137

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

1143
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
2,776✔
1144
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1145
    if length(ir_dest) != length(ir_src)
2,776✔
1146
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1147
            length(ir_src)," and ",length(ir_dest),")")))
1148
    end
1149
    if length(jr_dest) != length(jr_src)
2,775✔
1150
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1151
            length(jr_src)," and ",length(jr_dest),")")))
1152
    end
1153
    @boundscheck checkbounds(B, ir_dest, jr_dest)
2,775✔
1154
    @boundscheck checkbounds(A, ir_src, jr_src)
2,775✔
1155
    A′ = unalias(B, A)
5,548✔
1156
    jdest = first(jr_dest)
2,775✔
1157
    for jsrc in jr_src
5,550✔
1158
        idest = first(ir_dest)
19,662✔
1159
        for isrc in ir_src
39,324✔
1160
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
197,366✔
1161
            idest += step(ir_dest)
197,206✔
1162
        end
374,750✔
1163
        jdest += step(jr_dest)
19,662✔
1164
    end
36,549✔
1165
    return B
2,775✔
1166
end
1167

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

1170
function copyto_axcheck!(dest, src)
21,398✔
1171
    _checkaxs(axes(dest), axes(src))
183,636✔
1172
    copyto!(dest, src)
356,002✔
1173
end
1174

1175
"""
1176
    copymutable(a)
1177

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

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

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

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

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

1206
# While the definitions for IndexLinear are all simple enough to inline on their
1207
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1208
# inlining.
1209
function iterate(A::AbstractArray, state=(eachindex(A),))
110,983,780✔
1210
    y = iterate(state...)
134,474,292✔
1211
    y === nothing && return nothing
111,250,240✔
1212
    A[y[1]], (state[1], tail(y)...)
110,611,801✔
1213
end
1214

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

1217

1218
## range conversions ##
1219

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

1227
## unsafe/pointer conversions ##
1228

1229
# note: the following type definitions don't mean any AbstractArray is convertible to
1230
# a data Ref. they just map the array element type to the pointer type for
1231
# convenience in cases that work.
1232
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
45,487,959✔
1233
function pointer(x::AbstractArray{T}, i::Integer) where T
9,458,290✔
1234
    @inline
5,380,643✔
1235
    unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
391,447,545✔
1236
end
1237

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

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

1257
Return a subset of array `A` as specified by `inds`, where each `ind` may be,
1258
for example, an `Int`, an [`AbstractRange`](@ref), or a [`Vector`](@ref).
1259

1260
When `inds` selects multiple elements, this function returns a newly
1261
allocated array. To index multiple elements without making a copy,
1262
use [`view`](@ref) instead.
1263

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

1266
# Examples
1267
```jldoctest
1268
julia> A = [1 2; 3 4]
1269
2×2 Matrix{Int64}:
1270
 1  2
1271
 3  4
1272

1273
julia> getindex(A, 1)
1274
1
1275

1276
julia> getindex(A, [2, 1])
1277
2-element Vector{Int64}:
1278
 3
1279
 1
1280

1281
julia> getindex(A, 2:4)
1282
3-element Vector{Int64}:
1283
 3
1284
 2
1285
 4
1286
```
1287
"""
1288
function getindex(A::AbstractArray, I...)
95,910,587✔
1289
    @_propagate_inbounds_meta
95,561,722✔
1290
    error_if_canonical_getindex(IndexStyle(A), A, I...)
95,561,722✔
1291
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
238,293,683✔
1292
end
1293
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1294
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
238,200,680✔
1295

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

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

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

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

1314
## IndexLinear Scalar indexing: canonical method is one Int
1315
_getindex(::IndexLinear, A::AbstractVector, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))  # ambiguity resolution in case packages specialize this (to be avoided if at all possible, but see Interpolations.jl)
20,379,005✔
1316
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
×
1317
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
2,213,512✔
1318
    @inline
2,213,512✔
1319
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
38,520,759✔
1320
    @inbounds r = getindex(A, _to_linear_index(A, I...))
38,520,723✔
1321
    r
38,520,697✔
1322
end
1323
_to_linear_index(A::AbstractArray, i::Integer) = i
131,087✔
1324
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1,854,727✔
1325
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
289,004✔
1326
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
2,123,890✔
1327

1328
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1329
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
168,495✔
1330
    @inline
168,495✔
1331
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
168,508✔
1332
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
175,790✔
1333
    r
168,481✔
1334
end
1335
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
91,591,596✔
1336
    @_propagate_inbounds_meta
91,591,596✔
1337
    getindex(A, I...)
178,776,377✔
1338
end
1339
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
216,034✔
1340
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1341
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1342
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
5✔
1343
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1344
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1,798✔
1345
    @inline
1,798✔
1346
    J, Jrem = IteratorsMD.split(I, Val(N))
1,798✔
1347
    _to_subscript_indices(A, J, Jrem)
1,798✔
1348
end
1349
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1350
    __to_subscript_indices(A, axes(A), J, Jrem)
1351
function __to_subscript_indices(A::AbstractArray,
2✔
1352
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1353
    @inline
2✔
1354
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1355
end
1356
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
1,796✔
1357
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
24,382✔
1358
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1359
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1360
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1361
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
216,034✔
1362

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

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

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

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

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

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

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

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

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

1408
## IndexLinear Scalar indexing
1409
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
386,707✔
1410
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
159,215✔
1411
    @inline
153,209✔
1412
    @boundscheck checkbounds(A, I...)
164,050✔
1413
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
164,013✔
1414
    r
164,012✔
1415
end
1416

1417
# IndexCartesian Scalar indexing
1418
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,241,228✔
1419
    @_propagate_inbounds_meta
2,241,228✔
1420
    setindex!(A, v, I...)
2,241,327✔
1421
end
1422
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
917✔
1423
    @inline
917✔
1424
    @boundscheck checkbounds(A, I...)
922✔
1425
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
912✔
1426
    r
912✔
1427
end
1428

1429
"""
1430
    parent(A)
1431

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

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

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

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

1457
parent(a::AbstractArray) = a
1,525✔
1458

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

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

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

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

1473
See also [`Base.mightalias`](@ref).
1474
"""
1475
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
8,705,231✔
1476
unalias(dest, A::AbstractRange) = A
2,906,834✔
1477
unalias(dest, A) = A
2,585,255✔
1478

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

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

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

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

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

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

1513
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1514
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1515
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1516
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
9✔
1517
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
5,889,391✔
1518
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
59,730✔
1519
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1520
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
2,027✔
1521
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
73,002✔
1522

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

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

1528
Custom arrays that would like to opt-in to aliasing detection of their component
1529
parts can specialize this method to return the concatenation of the `dataids` of
1530
their component parts.  A typical definition for an array that wraps a parent is
1531
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1532
"""
1533
dataids(A::AbstractArray) = (UInt(objectid(A)),)
351,186✔
1534
dataids(A::Array) = (UInt(pointer(A)),)
11,520,500✔
1535
dataids(::AbstractRange) = ()
2,646,088✔
1536
dataids(x) = ()
2,962✔
1537

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

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

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

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

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

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

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

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

1584
## Concatenation ##
1585
eltypeof(x) = typeof(x)
21,329✔
1586
eltypeof(x::AbstractArray) = eltype(x)
1,092✔
1587

1588
promote_eltypeof() = error()
×
1589
promote_eltypeof(v1) = eltypeof(v1)
564✔
1590
promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
21,722✔
1591
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
135✔
1592
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
7,371✔
1593

1594
promote_eltype() = error()
×
1595
promote_eltype(v1) = eltype(v1)
121✔
1596
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
1,729✔
1597
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
11,364✔
1598
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
2,707✔
1599

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

1603
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1604
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1605

1606
## cat: special cases
1607
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
139✔
1608
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
174✔
1609
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
97✔
1610
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
462✔
1611

1612
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
31✔
1613
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
52✔
1614
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
10✔
1615
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
61✔
1616

1617
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
3✔
1618
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
4✔
1619

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

1625
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
792,051✔
1626
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
814,182✔
1627
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1628

1629
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
792,051✔
1630
    pos = 1
792,050✔
1631
    for k=1:Int(length(V))::Int
792,061✔
1632
        Vk = V[k]
792,881✔
1633
        p1 = pos + Int(length(Vk))::Int - 1
792,906✔
1634
        a[pos:p1] = Vk
5,704,540✔
1635
        pos = p1+1
792,881✔
1636
    end
793,711✔
1637
    a
792,051✔
1638
end
1639

1640
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
843✔
1641

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

1649

1650
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
174✔
1651
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
227✔
1652

1653
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
849✔
1654
    nargs = length(A)
849✔
1655
    nrows = size(A[1], 1)
850✔
1656
    ncols = 0
849✔
1657
    dense = true
849✔
1658
    for j = 1:nargs
855✔
1659
        Aj = A[j]
1,737✔
1660
        if size(Aj, 1) != nrows
2,359✔
1661
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1662
        end
1663
        dense &= isa(Aj,Array)
1,736✔
1664
        nd = ndims(Aj)
2,355✔
1665
        ncols += (nd==2 ? size(Aj,2) : 1)
2,097✔
1666
    end
2,624✔
1667
    B = similar(A[1], T, nrows, ncols)
848✔
1668
    pos = 1
848✔
1669
    if dense
848✔
1670
        for k=1:nargs
280✔
1671
            Ak = A[k]
578✔
1672
            n = length(Ak)
696✔
1673
            copyto!(B, pos, Ak, 1, n)
694✔
1674
            pos += n
578✔
1675
        end
878✔
1676
    else
1677
        for k=1:nargs
574✔
1678
            Ak = A[k]
1,157✔
1679
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
1,406✔
1680
            B[:, pos:p1] = Ak
1,535✔
1681
            pos = p1+1
1,157✔
1682
        end
1,648✔
1683
    end
1684
    return B
848✔
1685
end
1686

1687
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
51✔
1688
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
185✔
1689

1690
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
457✔
1691
    nargs = length(A)
457✔
1692
    nrows = sum(a->size(a, 1), A)::Int
1,495✔
1693
    ncols = size(A[1], 2)
457✔
1694
    for j = 2:nargs
458✔
1695
        if size(A[j], 2) != ncols
547✔
1696
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1697
        end
1698
    end
620✔
1699
    B = similar(A[1], T, nrows, ncols)
456✔
1700
    pos = 1
456✔
1701
    for k=1:nargs
457✔
1702
        Ak = A[k]
986✔
1703
        p1 = pos+size(Ak,1)::Int-1
1,135✔
1704
        B[pos:p1, :] = Ak
1,032✔
1705
        pos = p1+1
986✔
1706
    end
1,516✔
1707
    return B
456✔
1708
end
1709

1710
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
813,698✔
1711

1712
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1713
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1714

1715
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1716
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1717

1718
## cat: general case
1719

1720
# helper functions
1721
cat_size(A) = (1,)
22,369✔
1722
cat_size(A::AbstractArray) = size(A)
15,391✔
1723
cat_size(A, d) = 1
22,782✔
1724
cat_size(A::AbstractArray, d) = size(A, d)
23,095✔
1725

1726
cat_length(::Any) = 1
100✔
1727
cat_length(a::AbstractArray) = length(a)
472✔
1728

1729
cat_ndims(a) = 0
183✔
1730
cat_ndims(a::AbstractArray) = ndims(a)
684✔
1731

1732
cat_indices(A, d) = OneTo(1)
22,370✔
1733
cat_indices(A::AbstractArray, d) = axes(A, d)
16,498✔
1734

1735
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,364✔
1736
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1737
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,122✔
1738
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1739
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
438✔
1740
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1741

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

1757
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1758
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1759
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
450✔
1760
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
709✔
1761
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1762
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
2,572✔
1763
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1764
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
21✔
1765
    _cs(ndim, shape[1], 1)
23✔
1766
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
19✔
1767
end
1768
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
141✔
1769
    next = _cs(ndim, shape[1], nshape[1])
141✔
1770
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
141✔
1771
end
1772
@inline function _cshp(ndim::Int, dims, shape, nshape)
29,574✔
1773
    a = shape[1]
29,515✔
1774
    b = nshape[1]
29,515✔
1775
    next = dims[1] ? a + b : _cs(ndim, a, b)
30,076✔
1776
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
29,759✔
1777
end
1778

1779
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,005✔
1780
    "mismatch in dimension $d (expected $a got $b)")))
1781

1782
dims2cat(::Val{dims}) where dims = dims2cat(dims)
8,123✔
1783
function dims2cat(dims)
8,721✔
1784
    if any(≤(0), dims)
9,875✔
1785
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1786
    end
1787
    ntuple(in(dims), maximum(dims))
8,760✔
1788
end
1789

1790
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
8,011✔
1791

1792
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
8,725✔
1793
    catdims = dims2cat(dims)
8,762✔
1794
    shape = cat_size_shape(catdims, X...)
8,981✔
1795
    A = cat_similar(X[1], T, shape)
8,874✔
1796
    if count(!iszero, catdims)::Int > 1
8,719✔
1797
        fill!(A, zero(T))
571✔
1798
    end
1799
    return __cat(A, shape, catdims, X...)
9,400✔
1800
end
1801
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1802
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1803
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1804

1805
# Why isn't this called `__cat!`?
1806
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
9,404✔
1807

1808
function __cat_offset!(A, shape, catdims, offsets, x, X...)
37,749✔
1809
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1810
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
38,432✔
1811
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
37,904✔
1812
end
1813
__cat_offset!(A, shape, catdims, offsets) = A
8,721✔
1814

1815
function __cat_offset1!(A, shape, catdims, offsets, x)
37,594✔
1816
    inds = ntuple(length(offsets)) do i
38,055✔
1817
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
40,982✔
1818
    end
1819
    if x isa AbstractArray
37,594✔
1820
        A[inds...] = x
106,291✔
1821
    else
1822
        fill!(view(A, inds...), x)
23,405✔
1823
    end
1824
    newoffsets = ntuple(length(offsets)) do i
37,903✔
1825
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
41,939✔
1826
    end
1827
    return newoffsets
37,903✔
1828
end
1829

1830
"""
1831
    vcat(A...)
1832

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

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

1839
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1840

1841
# Examples
1842
```jldoctest
1843
julia> v = vcat([1,2], [3,4])
1844
4-element Vector{Int64}:
1845
 1
1846
 2
1847
 3
1848
 4
1849

1850
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1851
true
1852

1853
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1854
true
1855

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

1859
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1860
3-element Vector{Float64}:
1861
 1.0
1862
 1.5
1863
 2.0
1864

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

1868
julia> vcat(two...)
1869
3×3 Matrix{Float64}:
1870
 10.0  20.0  30.0
1871
  4.0   5.0   6.0
1872
  7.0   8.0   9.0
1873

1874
julia> vs = [[1, 2], [3, 4], [5, 6]];
1875

1876
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1877
6-element Vector{Int64}:
1878
 1
1879
 2
1880
 3
1881
 4
1882
 5
1883
 6
1884

1885
julia> ans == collect(Iterators.flatten(vs))
1886
true
1887
```
1888
"""
1889
vcat(X...) = cat(X...; dims=Val(1))
535✔
1890
"""
1891
    hcat(A...)
1892

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

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

1900
See also [`vcat`](@ref), [`hvcat`](@ref).
1901

1902
# Examples
1903
```jldoctest
1904
julia> hcat([1,2], [3,4], [5,6])
1905
2×3 Matrix{Int64}:
1906
 1  3  5
1907
 2  4  6
1908

1909
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1910
1×7 Matrix{Int64}:
1911
 1  2  30  40  5  6  7
1912

1913
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1914
true
1915

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

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

1922
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
1923
2×6 Matrix{Float64}:
1924
 0.0  0.0  1.0  2.0  50.0  60.0
1925
 0.0  0.0  3.0  4.0  70.0  80.0
1926

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

1930
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
1931
0×3 Matrix{Int64}
1932

1933
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
1934
2×1 Matrix{Any}:
1935
 1.1
1936
 9.9
1937
```
1938
"""
1939
hcat(X...) = cat(X...; dims=Val(2))
9✔
1940

1941
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
186✔
1942
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
328✔
1943

1944
"""
1945
    cat(A...; dims)
1946

1947
Concatenate the input arrays along the dimensions specified in `dims`.
1948

1949
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
1950
a in A)`.
1951
Along other dimensions, all input arrays should have the same size,
1952
which will also be the size of the output array along those dimensions.
1953

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

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

1963
The keyword also accepts `Val(dims)`.
1964

1965
!!! compat "Julia 1.8"
1966
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
1967

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

1976
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
1977
4×7 Matrix{Bool}:
1978
 1  0  0  0  0  0  0
1979
 0  1  1  0  0  0  0
1980
 0  1  1  0  0  0  0
1981
 0  0  0  1  1  1  1
1982

1983
julia> cat(1, [2], [3;;]; dims=Val(2))
1984
1×3 Matrix{Int64}:
1985
 1  2  3
1986
```
1987
"""
1988
@inline cat(A...; dims) = _cat(dims, A...)
16,756✔
1989
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
1990
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
144✔
1991

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

2003
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
2004
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2005
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
2006
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2007
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
2008
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
2009

2010
# 2d horizontal and vertical concatenation
2011

2012
# these are produced in lowering if splatting occurs inside hvcat
2013
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
3✔
2014
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
3✔
2015

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

2025
"""
2026
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2027

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

2033
# Examples
2034
```jldoctest
2035
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2036
(1, 2, 3, 4, 5, 6)
2037

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

2043
julia> hvcat((3,3), a,b,c,d,e,f)
2044
2×3 Matrix{Int64}:
2045
 1  2  3
2046
 4  5  6
2047

2048
julia> [a b; c d; e f]
2049
3×2 Matrix{Int64}:
2050
 1  2
2051
 3  4
2052
 5  6
2053

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

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

2069
    nc = 0
679✔
2070
    for i=1:rows[1]
1,358✔
2071
        nc += size(as[i],2)
1,982✔
2072
    end
1,973✔
2073

2074
    nr = 0
679✔
2075
    a = 1
679✔
2076
    for i = 1:nbr
679✔
2077
        nr += size(as[a],1)
1,469✔
2078
        a += rows[i]
1,181✔
2079
    end
1,683✔
2080

2081
    out = similar(as[1], T, nr, nc)
679✔
2082

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

2109
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2110
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2111

2112
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,285✔
2113
    nr = length(rows)
1,267✔
2114
    nc = rows[1]
1,285✔
2115

2116
    a = Matrix{T}(undef, nr, nc)
1,285✔
2117
    if length(a) != length(xs)
1,285✔
2118
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2119
    end
2120
    k = 1
1,265✔
2121
    @inbounds for i=1:nr
1,301✔
2122
        if nc != rows[i]
3,488✔
2123
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2124
        end
2125
        for j=1:nc
6,974✔
2126
            a[i,j] = xs[k]
9,604✔
2127
            k += 1
9,604✔
2128
        end
15,721✔
2129
    end
5,692✔
2130
    a
1,282✔
2131
end
2132

2133
function hvcat_fill!(a::Array, xs::Tuple)
555✔
2134
    nr, nc = size(a,1), size(a,2)
555✔
2135
    len = length(xs)
555✔
2136
    if nr*nc != len
555✔
2137
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2138
    end
2139
    k = 1
554✔
2140
    for i=1:nr
1,108✔
2141
        @inbounds for j=1:nc
2,930✔
2142
            a[i,j] = xs[k]
9,692✔
2143
            k += 1
8,988✔
2144
        end
16,511✔
2145
    end
2,376✔
2146
    a
554✔
2147
end
2148

2149
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
176✔
2150
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
138✔
2151
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2152
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
3✔
2153

2154
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
403✔
2155
    nr = length(rows)
403✔
2156
    nc = rows[1]
403✔
2157
    for i = 2:nr
403✔
2158
        if nc != rows[i]
791✔
2159
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2160
        end
2161
    end
1,177✔
2162
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
401✔
2163
end
2164

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

2176
## N-dimensional concatenation ##
2177

2178
"""
2179
    hvncat(dim::Int, row_first, values...)
2180
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2181
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2182

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

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

2196
# Examples
2197
```jldoctest
2198
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2199
(1, 2, 3, 4, 5, 6)
2200

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

2206
[:, :, 2] =
2207
 4  5  6
2208

2209
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2210
2×1×3 Array{Int64, 3}:
2211
[:, :, 1] =
2212
 1
2213
 2
2214

2215
[:, :, 2] =
2216
 3
2217
 4
2218

2219
[:, :, 3] =
2220
 5
2221
 6
2222

2223
julia> [a b;;; c d;;; e f]
2224
1×2×3 Array{Int64, 3}:
2225
[:, :, 1] =
2226
 1  2
2227

2228
[:, :, 2] =
2229
 3  4
2230

2231
[:, :, 3] =
2232
 5  6
2233

2234
julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2235
1×3×2 Array{Int64, 3}:
2236
[:, :, 1] =
2237
 1  2  3
2238

2239
[:, :, 2] =
2240
 4  5  6
2241
```
2242

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

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

2266
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
29✔
2267
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
91✔
2268
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
88✔
2269
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2270
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2271
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
132✔
2272

2273

2274
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2275
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2276

2277
# 1-dimensional hvncat methods
2278

2279
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
4✔
2280
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2281
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
4✔
2282
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
4✔
2283
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2284
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
4✔
2285
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2286

2287
_typed_hvncat_0d_only_one() =
8✔
2288
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2289

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

2293
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
15✔
2294
    N < 0 &&
15✔
2295
        throw(ArgumentError("concatenation dimension must be non-negative"))
2296
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
40✔
2297
end
2298

2299
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
38✔
2300
    N < 0 &&
38✔
2301
        throw(ArgumentError("concatenation dimension must be non-negative"))
2302
    A = cat_similar(xs[1], T, (ntuple(x -> 1, Val(N - 1))..., length(xs)))
83✔
2303
    hvncat_fill!(A, false, xs)
37✔
2304
    return A
37✔
2305
end
2306

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

2320
    nd = N
17✔
2321

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

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

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

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

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

2374
# 0-dimensional cases for balanced and unbalanced hvncat method
2375

2376
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2377
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2378

2379

2380
# balanced dimensions hvncat methods
2381

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

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

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

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

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

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

2452
    d1 = row_first ? 2 : 1
58✔
2453
    d2 = row_first ? 1 : 2
58✔
2454

2455
    outdims = zeros(Int, N)
203✔
2456

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

2478
    # discover number of rows or columns
2479
    for i ∈ 1:dims[d1]
104✔
2480
        outdims[d1] += cat_size(as[i], d1)
140✔
2481
    end
164✔
2482

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

2517
    outlen = prod(outdims)
72✔
2518
    elementcount == outlen ||
36✔
2519
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2520

2521
    # copy into final array
2522
    A = cat_similar(as[1], T, outdims)
36✔
2523
    # @assert all(==(0), currentdims)
2524
    outdims .= 0
108✔
2525
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
36✔
2526
    return A
36✔
2527
end
2528

2529

2530
# unbalanced dimensions hvncat methods
2531

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

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

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

2550
    d1 = row_first ? 2 : 1
67✔
2551
    d2 = row_first ? 1 : 2
67✔
2552

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

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

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

2584
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
899✔
2585

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

2604
    outlen = prod(outdims)
30✔
2605
    elementcount == outlen ||
15✔
2606
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2607

2608
    if row_first
15✔
2609
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2610
    end
2611

2612
    # @assert all(==(0), currentdims)
2613
    # @assert all(==(0), blockcounts)
2614

2615
    # copy into final array
2616
    A = cat_similar(as[1], T, outdims)
15✔
2617
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
15✔
2618
    return A
15✔
2619
end
2620

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

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

2650
        @inbounds for j ∈ (d1, d2, 3:N...)
270✔
2651
            offsets[j] += cat_size(a, j)
599✔
2652
            offsets[j] < outdims[j] && break
518✔
2653
            offsets[j] = 0
304✔
2654
        end
304✔
2655
    end
270✔
2656
end
2657

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

2671
"""
2672
    stack(iter; [dims])
2673

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

2677
By default the axes of the elements are placed first,
2678
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2679
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2680

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

2685
The various [`cat`](@ref) functions also combine arrays. However, these all
2686
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2687
the arrays along new dimensions.
2688
They also accept arrays as separate arguments, rather than a single collection.
2689

2690
!!! compat "Julia 1.9"
2691
    This function requires at least Julia 1.9.
2692

2693
# Examples
2694
```jldoctest
2695
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2696

2697
julia> mat = stack(vecs)
2698
2×3 Matrix{Float32}:
2699
 1.0  30.0  500.0
2700
 2.0  40.0  600.0
2701

2702
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2703
true
2704

2705
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2706
true
2707

2708
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2709
2×4 Matrix{Int64}:
2710
  1   2   3   4
2711
 10  11  12  13
2712

2713
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2714
true
2715

2716
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2717
3×2 Matrix{Float32}:
2718
   1.0    2.0
2719
  30.0   40.0
2720
 500.0  600.0
2721

2722
julia> x = rand(3,4);
2723

2724
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2725
true
2726
```
2727

2728
Higher-dimensional examples:
2729

2730
```jldoctest
2731
julia> A = rand(5, 7, 11);
2732

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

2735
julia> (element = size(first(E)), container = size(E))
2736
(element = (5, 11), container = (7,))
2737

2738
julia> stack(E) |> size
2739
(5, 11, 7)
2740

2741
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2742
true
2743

2744
julia> A == stack(E; dims=2)
2745
true
2746

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

2749
julia> (element = size(first(M)), container = size(M))
2750
(element = (2, 3), container = (5, 7))
2751

2752
julia> stack(M) |> size  # keeps all dimensions
2753
(2, 3, 5, 7)
2754

2755
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2756
(35, 2, 3)
2757

2758
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2759
(14, 15)
2760
```
2761
"""
2762
stack(iter; dims=:) = _stack(dims, iter)
250✔
2763

2764
"""
2765
    stack(f, args...; [dims])
2766

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

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

2774
See also [`mapslices`](@ref), [`eachcol`](@ref).
2775

2776
# Examples
2777
```jldoctest
2778
julia> stack(c -> (c, c-32), "julia")
2779
2×5 Matrix{Char}:
2780
 'j'  'u'  'l'  'i'  'a'
2781
 'J'  'U'  'L'  'I'  'A'
2782

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

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

2796
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2797

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

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

2829
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2830
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2831
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2832

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

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

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

2858
    newaxis = _vec_axis(A)
21✔
2859
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
141✔
2860
    B = similar(_ensure_array(x1), T, outax...)
23✔
2861

2862
    if dims == 1
21✔
2863
        _dim_stack!(Val(1), B, x1, xrest)
13✔
2864
    elseif dims == 2
8✔
2865
        _dim_stack!(Val(2), B, x1, xrest)
4✔
2866
    else
2867
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
2868
    end
2869
    B
18✔
2870
end
2871

2872
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
2873
    before = ntuple(d -> Colon(), dims - 1)
33✔
2874
    after = ntuple(d -> Colon(), ndims(B) - dims)
49✔
2875

2876
    i = firstindex(B, dims)
21✔
2877
    copyto!(view(B, before..., i, after...), x1)
40✔
2878

2879
    for x in xrest
29✔
2880
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
2881
        i += 1
3,261✔
2882
        @inbounds copyto!(view(B, before..., i, after...), x)
6,415✔
2883
    end
3,261✔
2884
end
2885

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

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

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

2900

2901
## Reductions and accumulates ##
2902

2903
function isequal(A::AbstractArray, B::AbstractArray)
248,240✔
2904
    if A === B return true end
248,493✔
2905
    if axes(A) != axes(B)
493,041✔
2906
        return false
2,915✔
2907
    end
2908
    for (a, b) in zip(A, B)
489,563✔
2909
        if !isequal(a, b)
92,615,270✔
2910
            return false
474✔
2911
        end
2912
    end
184,781,497✔
2913
    return true
244,598✔
2914
end
2915

2916
function cmp(A::AbstractVector, B::AbstractVector)
297✔
2917
    for (a, b) in zip(A, B)
594✔
2918
        if !isequal(a, b)
812✔
2919
            return isless(a, b) ? -1 : 1
282✔
2920
        end
2921
    end
1,045✔
2922
    return cmp(length(A), length(B))
15✔
2923
end
2924

2925
"""
2926
    isless(A::AbstractVector, B::AbstractVector)
2927

2928
Return `true` when `A` is less than `B` in lexicographic order.
2929
"""
2930
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
288✔
2931

2932
function (==)(A::AbstractArray, B::AbstractArray)
6,568,725✔
2933
    if axes(A) != axes(B)
13,134,276✔
2934
        return false
3,573✔
2935
    end
2936
    anymissing = false
6,562,600✔
2937
    for (a, b) in zip(A, B)
12,244,177✔
2938
        eq = (a == b)
135,902,338✔
2939
        if ismissing(eq)
103,986,859✔
2940
            anymissing = true
24✔
2941
        elseif !eq
135,013,872✔
2942
            return false
2,768✔
2943
        end
2944
    end
264,346,188✔
2945
    return anymissing ? missing : true
6,562,623✔
2946
end
2947

2948
# _sub2ind and _ind2sub
2949
# fallbacks
2950
function _sub2ind(A::AbstractArray, I...)
2,099,075✔
2951
    @inline
2,099,075✔
2952
    _sub2ind(axes(A), I...)
2,123,890✔
2953
end
2954

2955
function _ind2sub(A::AbstractArray, ind)
216,035✔
2956
    @inline
216,035✔
2957
    _ind2sub(axes(A), ind)
216,035✔
2958
end
2959

2960
# 0-dimensional arrays and indexing with []
2961
_sub2ind(::Tuple{}) = 1
18✔
2962
_sub2ind(::DimsInteger) = 1
2✔
2963
_sub2ind(::Indices) = 1
×
2964
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
5✔
2965

2966
# Generic cases
2967
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
2,147,483,647✔
2968
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
2,242,039✔
2969
# In 1d, there's a question of whether we're doing cartesian indexing
2970
# or linear indexing. Support only the former.
2971
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
2972
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2973
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
2974
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
2975

2976
_sub2ind_recurse(::Any, L, ind) = ind
1,306,193✔
2977
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,796✔
2978
    @inline
867✔
2979
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
12,149✔
2980
end
2981
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
6,538,247✔
2982
    @inline
6,404,699✔
2983
    r1 = inds[1]
6,404,701✔
2984
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
2,147,483,647✔
2985
end
2986

2987
nextL(L, l::Integer) = L*l
1,460,407✔
2988
nextL(L, r::AbstractUnitRange) = L*length(r)
4,980,590✔
2989
nextL(L, r::Slice) = L*length(r.indices)
×
2990
offsetin(i, l::Integer) = i-1
2,147,483,647✔
2991
offsetin(i, r::AbstractUnitRange) = i-first(r)
5,005,827✔
2992

2993
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
2994
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
1,223✔
2995
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
216,047✔
2996
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
2997
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2998
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
12✔
2999

3000
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3001
function _ind2sub_recurse(indslast::NTuple{1}, ind)
217,270✔
3002
    @inline
217,270✔
3003
    (_lookup(ind, indslast[1]),)
217,270✔
3004
end
3005
function _ind2sub_recurse(inds, ind)
380,007✔
3006
    @inline
380,007✔
3007
    r1 = inds[1]
380,007✔
3008
    indnext, f, l = _div(ind, r1)
380,007✔
3009
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
380,007✔
3010
end
3011

3012
_lookup(ind, d::Integer) = ind+1
1,223✔
3013
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
216,047✔
3014
_div(ind, d::Integer) = div(ind, d), 1, d
1,223✔
3015
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
757,568✔
3016

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

3036
function _sub2ind!(Iout, inds, Iinds, I)
×
3037
    @noinline
×
3038
    for i in Iinds
×
3039
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3040
        Iout[i] = sub2ind_vec(inds, i, I)
×
3041
    end
×
3042
    Iout
×
3043
end
3044

3045
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3046
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3047
_sub2ind_vec(i) = ()
×
3048

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

3061
## iteration utilities ##
3062

3063
"""
3064
    foreach(f, c...) -> Nothing
3065

3066
Call function `f` on each element of iterable `c`.
3067
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3068
any iterator is finished.
3069

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

3073
# Examples
3074
```jldoctest
3075
julia> tri = 1:3:7; res = Int[];
3076

3077
julia> foreach(x -> push!(res, x^2), tri)
3078

3079
julia> res
3080
3-element Vector{$(Int)}:
3081
  1
3082
 16
3083
 49
3084

3085
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3086
1 with a
3087
4 with b
3088
7 with c
3089
```
3090
"""
3091
foreach(f) = (f(); nothing)
2✔
3092
foreach(f, itr) = (for x in itr; f(x); end; nothing)
513,621,776✔
3093
foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
11✔
3094

3095
## map over arrays ##
3096

3097
## transform any set of dimensions
3098
## dims specifies which dimensions will be transformed. for example
3099
## dims==1:2 will call f on all slices A[:,:,...]
3100
"""
3101
    mapslices(f, A; dims)
3102

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

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

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

3112
# Examples
3113
```jldoctest
3114
julia> A = reshape(1:30,(2,5,3))
3115
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3116
[:, :, 1] =
3117
 1  3  5  7   9
3118
 2  4  6  8  10
3119

3120
[:, :, 2] =
3121
 11  13  15  17  19
3122
 12  14  16  18  20
3123

3124
[:, :, 3] =
3125
 21  23  25  27  29
3126
 22  24  26  28  30
3127

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

3130
julia> B = mapslices(f, A, dims=(1,2))
3131
1×4×3 Array{$Int, 3}:
3132
[:, :, 1] =
3133
 1  1  1  1
3134

3135
[:, :, 2] =
3136
 11  11  11  11
3137

3138
[:, :, 3] =
3139
 21  21  21  21
3140

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

3143
julia> B == stack(f2, eachslice(A, dims=3))
3144
true
3145

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

3148
julia> mapslices(g, A, dims=[1,3])
3149
1×5×1 Array{Rational{$Int}, 3}:
3150
[:, :, 1] =
3151
 1//21  3//23  1//5  7//27  9//29
3152

3153
julia> map(g, eachslice(A, dims=2))
3154
5-element Vector{Rational{$Int}}:
3155
 1//21
3156
 3//23
3157
 1//5
3158
 7//27
3159
 9//29
3160

3161
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3162
true
3163
```
3164

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

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

3183
    # Apply the function to the first slice in order to determine the next steps
3184
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3,156✔
3185
    Aslice = A[idx1...]
829✔
3186
    r1 = f(Aslice)
531✔
3187

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

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

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

3220
    # That skips the first element, which we already have:
3221
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
2,581✔
3222
    concatenate_setindex!(R, res1, ridx...)
455✔
3223

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

3231
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
468✔
3232
    return R
442✔
3233
end
3234

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

3262
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
3,702✔
3263
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
448✔
3264

3265
## 0 arguments
3266

3267
map(f) = f()
1✔
3268

3269
## 1 argument
3270

3271
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,238✔
3272
    for (i,j) in zip(eachindex(dest),eachindex(A))
296,239,797✔
3273
        val = f(@inbounds A[j])
316,388,922✔
3274
        @inbounds dest[i] = val
184,846,522✔
3275
    end
232,090,101✔
3276
    return dest
158,839,072✔
3277
end
3278

3279
# map on collections
3280
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
94,182✔
3281

3282
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
2,495✔
3283
mapany(f, itr) = Any[f(x) for x in itr]
×
3284

3285
"""
3286
    map(f, c...) -> collection
3287

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

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

3293
# Examples
3294
```jldoctest
3295
julia> map(x -> x * 2, [1, 2, 3])
3296
3-element Vector{Int64}:
3297
 2
3298
 4
3299
 6
3300

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

3310
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3311
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3312

3313
## 2 argument
3314
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
364✔
3315
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
715✔
3316
        @inbounds a, b = A[j], B[k]
387,040✔
3317
        val = f(a, b)
338,192✔
3318
        @inbounds dest[i] = val
338,192✔
3319
    end
676,033✔
3320
    return dest
364✔
3321
end
3322

3323
## N argument
3324

3325
@inline ith_all(i, ::Tuple{}) = ()
4,030✔
3326
function ith_all(i, as)
12,090✔
3327
    @_propagate_inbounds_meta
12,090✔
3328
    return (as[1][i], ith_all(i, tail(as))...)
18,930✔
3329
end
3330

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

3342
"""
3343
    map!(function, destination, collection...)
3344

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

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

3350
# Examples
3351
```jldoctest
3352
julia> a = zeros(3);
3353

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

3356
julia> a
3357
3-element Vector{Float64}:
3358
 2.0
3359
 4.0
3360
 6.0
3361

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

3377
"""
3378
    map(f, A::AbstractArray...) -> N-array
3379

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

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

3385
# Examples
3386
```
3387
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3388
2×2 Matrix{Rational{$Int}}:
3389
 1//4  2//3
3390
 3//2  4//1
3391

3392
julia> map(+, [1 2; 3 4], zeros(2,1))
3393
ERROR: DimensionMismatch
3394

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

3404
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3405
# (note: must not cause a dispatch loop when 1-item case is not defined)
3406
push!(A, a, b) = push!(push!(A, a), b)
999✔
3407
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
2✔
3408
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3409
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
2✔
3410

3411
## hashing AbstractArray ##
3412

3413
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3414
function hash(A::AbstractArray, h::UInt)
19,936✔
3415
    h += hash_abstractarray_seed
19,936✔
3416
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3417
    # Instead hash the tuple of firsts and lasts along each dimension
3418
    h = hash(map(first, axes(A)), h)
20,173✔
3419
    h = hash(map(last, axes(A)), h)
20,173✔
3420

3421
    # For short arrays, it's not worth doing anything complicated
3422
    if length(A) < 8192
20,173✔
3423
        for x in A
23,763✔
3424
            h = hash(x, h)
4,634,298✔
3425
        end
4,777,998✔
3426
        return h
19,932✔
3427
    end
3428

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

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

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

3450
    # Start at the last index
3451
    keyidx = last(ks)
4✔
3452
    linidx = key_to_linear[keyidx]
4✔
3453
    fibskip = prevfibskip = oneunit(linidx)
4✔
3454
    first_linear = first(LinearIndices(linear_to_key))
4✔
3455
    n = 0
4✔
3456
    while true
28,192✔
3457
        n += 1
28,192✔
3458
        # Hash the element
3459
        elt = A[keyidx]
28,192✔
3460
        h = hash(keyidx=>elt, h)
56,384✔
3461

3462
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3463
        linidx = key_to_linear[keyidx]
28,192✔
3464
        linidx < fibskip + first_linear && break
28,192✔
3465
        linidx -= fibskip
28,188✔
3466
        keyidx = linear_to_key[linidx]
28,188✔
3467

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

3478
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3479
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3480
        keyidx === nothing && break
28,188✔
3481
    end
28,188✔
3482

3483
    return h
4✔
3484
end
3485

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

3494

3495
## keepat! ##
3496

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

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

3517
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
5✔
3518
    length(m) == length(a) || throw(BoundsError(a, m))
7✔
3519
    j = firstindex(a)
3✔
3520
    for i in eachindex(a, m)
5✔
3521
        @inbounds begin
20✔
3522
            if m[i]
20✔
3523
                i == j || (a[j] = a[i])
18✔
3524
                j = nextind(a, j)
9✔
3525
            end
3526
        end
3527
    end
38✔
3528
    deleteat!(a, j:lastindex(a))
3✔
3529
end
3530

3531
## 1-d circshift ##
3532
function circshift!(a::AbstractVector, shift::Integer)
1,101✔
3533
    n = length(a)
1,101✔
3534
    n == 0 && return
1,101✔
3535
    shift = mod(shift, n)
2,202✔
3536
    shift == 0 && return
1,101✔
3537
    l = lastindex(a)
773✔
3538
    reverse!(a, firstindex(a), l-shift)
773✔
3539
    reverse!(a, l-shift+1, lastindex(a))
773✔
3540
    reverse!(a)
773✔
3541
    return a
773✔
3542
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

© 2025 Coveralls, Inc