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

JuliaLang / julia / #38043

12 Apr 2025 06:53AM UTC coverage: 19.945% (-0.3%) from 20.228%
#38043

push

local

web-flow
Eagerly evaluate indices in `eachindex` check (#58054)

This reduces TTFX in `eachindex` calls with multiple arguments, with
minimal impact on performance. Much of the latency comes from the error
path, and specializing it for the common case of 2 arguments helps a lot
with reducing latency. In this, I've also unrolled the `join` in the
error path, and we recursively generate a `LazyString`s instead. This
helps in reducing TTFX for a longer list of arguments.

```julia
julia> a = zeros(2,2);

julia> @time eachindex(a, a);
  0.046902 seconds (128.39 k allocations: 6.652 MiB, 99.93% compilation time) # nightly
  0.015368 seconds (19.91 k allocations: 1.048 MiB, 99.79% compilation time) # this PR

julia> @btime eachindex($a, $a, $a, $a, $a, $a, $a, $a);
  6.945 ns (0 allocations: 0 bytes) # nightly
  6.855 ns (0 allocations: 0 bytes) # this PR
```
This reduces TTFX for a longer list of arguments as well:
```julia
julia> @time eachindex(a, a, a, a, a, a, a, a);
  0.052552 seconds (196.87 k allocations: 10.068 MiB, 99.53% compilation time) # nightly
  0.043401 seconds (69.13 k allocations: 3.454 MiB, 99.34% compilation time) # this PR
```
For Cartesian indexing,
```julia
julia> a = zeros(2,2);

julia> v = view(a, 1:2, 1:2);

julia> @time eachindex(a, v);
  0.051333 seconds (171.34 k allocations: 8.921 MiB, 99.94% compilation time) # nightly
  0.016340 seconds (26.95 k allocations: 1.405 MiB, 99.79% compilation time) # this PR

julia> @btime eachindex($a, $v, $a, $v, $a, $v, $a, $v);
  9.339 ns (0 allocations: 0 bytes) # nightly
  9.357 ns (0 allocations: 0 bytes) # this PR
```

0 of 10 new or added lines in 3 files covered. (0.0%)

957 existing lines in 13 files now uncovered.

9861 of 49441 relevant lines covered (19.94%)

98617.35 hits per line

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

16.47
/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
×
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
×
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
×
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
13,455✔
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}
76
    @inline
43,746✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
65,250✔
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)
2,585✔
97
    @inline
41,001✔
98
    map(unchecked_oneto, size(A))
6,950,680✔
99
end
100

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

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

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

120

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

215
prevind(::AbstractArray, i::Integer) = Int(i)-1
370✔
216
nextind(::AbstractArray, i::Integer) = Int(i)+1
58,371✔
217

218

219
"""
220
    eltype(type)
221

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

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

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

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

244
"""
245
    elsize(type)
246

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

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

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

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

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

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

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

278
"""
279
    length(collection)::Integer
280

281
Return the number of elements in the collection.
282

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

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

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

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

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

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

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

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

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

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

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

323

324
# we unroll the join for easier inference
NEW
325
_join_comma_and(indsA, indsB) = LazyString(indsA, " and ", indsB)
×
NEW
326
_join_comma_and(indsA, indsB, indsC...) = LazyString(indsA, ", ", _join_comma_and(indsB, indsC...))
×
NEW
327
@noinline function throw_eachindex_mismatch_indices(indices_str, indsA, indsBs...)
×
NEW
328
    throw(DimensionMismatch(
×
329
            LazyString("all inputs to eachindex must have the same ", indices_str, ", got ",
330
                _join_comma_and(indsA, indsBs...))))
331
end
332

333
"""
334
    eachindex(A...)
335
    eachindex(::IndexStyle, A::AbstractArray...)
336

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

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

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

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

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

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

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

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

382
function eachindex(A::AbstractArray, B::AbstractArray)
×
383
    @inline
×
384
    eachindex(IndexStyle(A,B), A, B)
×
385
end
386
function eachindex(A::AbstractArray, B::AbstractArray...)
×
387
    @inline
×
388
    eachindex(IndexStyle(A,B...), A, B...)
×
389
end
390
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
×
391
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
3,481,598✔
392
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
×
393
    @inline
×
394
    indsA = eachindex(IndexLinear(), A)
×
NEW
395
    indsBs = map(X -> eachindex(IndexLinear(), X), B)
×
NEW
396
    all(==(indsA), indsBs) ||
×
397
        throw_eachindex_mismatch_indices("indices", indsA, indsBs...)
UNCOV
398
    indsA
×
399
end
400

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

404
"""
405
    lastindex(collection)::Integer
406
    lastindex(collection, d)::Integer
407

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

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

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

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

420
julia> lastindex(rand(3,4,5), 2)
421
4
422
```
423
"""
424
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
1,253,972✔
425
lastindex(a, d) = (@inline; last(axes(a, d)))
1,119✔
426

427
"""
428
    firstindex(collection)::Integer
429
    firstindex(collection, d)::Integer
430

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

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

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

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

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

450
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
172✔
451

452
"""
453
    first(coll)
454

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

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

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

465
julia> first([1; 2; 3; 4])
466
1
467
```
468
"""
469
function first(itr)
×
470
    x = iterate(itr)
×
471
    x === nothing && throw(ArgumentError("collection must be non-empty"))
×
472
    x[1]
×
473
end
474

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

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

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

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

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

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

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

507
"""
508
    last(coll)
509

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

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

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

521
julia> last([1; 2; 3; 4])
522
4
523
```
524
"""
525
last(a) = a[end]
46,104✔
526

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

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

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

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

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

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

557
"""
558
    strides(A)
559

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

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

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

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

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

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

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

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

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

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

604
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
×
605
size_to_strides(s, d) = (s,)
×
606
size_to_strides(s) = ()
×
607

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

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

634
## Bounds checking ##
635

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

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

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

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

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

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

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

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

673
julia> checkbounds(Bool, A, 1:3, 2:4)
674
false
675
```
676
"""
677
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
678
    @inline
×
679
    checkbounds_indices(Bool, axes(A), I)
123,761✔
680
end
681

682
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index;
683
# indices that do not allow linear indexing (e.g., logical arrays, cartesian indices, etc)
684
# must add specialized methods to implement their restrictions
685
function checkbounds(::Type{Bool}, A::AbstractArray, i)
1,292✔
686
    @inline
415,868✔
687
    return checkindex(Bool, eachindex(IndexLinear(), A), i)
3,703,338✔
688
end
689

690
"""
691
    checkbounds(A, I...)
692

693
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
694
"""
695
function checkbounds(A::AbstractArray, I...)
1,292✔
696
    @inline
415,868✔
697
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
1,985,838✔
698
    nothing
415,868✔
699
end
700

701
"""
702
    checkbounds_indices(Bool, IA, I)
703

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

709
    checkbounds_indices(Bool, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
710
                                                          checkbounds_indices(Bool, IA, I)
711

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

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

719
See also [`checkbounds`](@ref).
720
"""
721
function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{Any, Vararg})
722
    @inline
×
723
    return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
246,946✔
724
        checkbounds_indices(Bool, safe_tail(inds), tail(I))
725
end
726

727
checkbounds_indices(::Type{Bool}, inds::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, inds))
×
728

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

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

738
See also [`checkbounds`](@ref).
739

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

745
julia> checkindex(Bool, 1:20, 21)
746
false
747
```
748
"""
749
checkindex(::Type{Bool}, inds, i) = throw(ArgumentError(LazyString("unable to check bounds for indices of type ", typeof(i))))
×
750
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
1,488,408✔
751
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
×
752
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
3,262,387✔
753
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
×
754
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
×
755
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::AbstractRange) =
1,580,407✔
756
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
757
# range like indices with cheap `extrema`
758
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::LinearIndices) =
×
759
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
760

761
function checkindex(::Type{Bool}, inds, I::AbstractArray)
762
    @inline
×
763
    b = true
×
764
    for i in I
2,482✔
765
        b &= checkindex(Bool, inds, i)
27,869✔
766
    end
27,869✔
767
    b
2,482✔
768
end
769

770
# See also specializations in multidimensional
771

772
## Constructors ##
773

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

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

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

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

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

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

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

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

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

816
See also: [`undef`](@ref), [`isassigned`](@ref).
817
"""
818
similar(a::AbstractArray{T}) where {T}                             = similar(a, T)
×
819
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, axes(a))
×
820
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, dims)
534,715✔
821
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, dims)
×
822
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, dims)
13,852✔
823
# Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
824
# thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
825
# but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
826
# define this method to convert supported axes to Ints, with the expectation that an offset array
827
# package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
828
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, AbstractOneTo}, Vararg{Union{Integer, AbstractOneTo}}}) where {T} = similar(a, T, to_shape(dims))
×
829
# legacy method for packages that specialize similar(A::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo, CustomAxis}, Vararg{Union{Integer, OneTo, CustomAxis}}}
830
# leaving this method in ensures that Base owns the more specific method
831
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
534,919✔
832
# similar creates an Array by default
833
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N}    = Array{T,N}(undef, dims)
13,849✔
834

835
to_shape(::Tuple{}) = ()
×
836
to_shape(dims::Dims) = dims
×
837
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
6,592✔
838
# each dimension
839
to_shape(i::Int) = i
×
840
to_shape(i::Integer) = Int(i)
×
841
to_shape(r::AbstractOneTo) = Int(last(r))
6,591✔
842
to_shape(r::AbstractUnitRange) = r
×
843

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

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

851
**Examples**:
852

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

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

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

863
would create a 1-dimensional logical array whose indices match those
864
of the columns of `A`.
865
"""
866
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
×
867
similar(::Type{T}, shape::Tuple{Union{Integer, AbstractOneTo}, Vararg{Union{Integer, AbstractOneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
×
868
# legacy method for packages that specialize similar(::Type{T}, dims::Tuple{Union{Integer, OneTo, CustomAxis}, Vararg{Union{Integer, OneTo, CustomAxis}})
869
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
80,770✔
870
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
80,770✔
871

872
"""
873
    empty(v::AbstractVector, [eltype])
874

875
Create an empty vector similar to `v`, optionally changing the `eltype`.
876

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

879
# Examples
880

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

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

891
# like empty, but should return a mutable collection, a Vector by default
892
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
2✔
893
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
×
894

895
"""
896
    copy!(dst, src) -> dst
897

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

905
$(_DOCS_ALIASING_WARNING)
906

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

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

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

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

932
## from general iterable to any array
933

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

938
function copyto!(dest::AbstractArray, src)
13,450✔
939
    destiter = eachindex(dest)
13,450✔
940
    y = iterate(destiter)
13,450✔
941
    for x in src
26,957✔
942
        y === nothing &&
68,236✔
943
            throw(ArgumentError("destination has fewer elements than required"))
944
        dest[y[1]] = x
68,236✔
945
        y = iterate(destiter, y[2])
123,419✔
946
    end
124,057✔
947
    return dest
13,450✔
948
end
949

950
function copyto!(dest::AbstractArray, dstart::Integer, src)
×
951
    i = Int(dstart)
×
952
    if haslength(src) && length(dest) > 0
×
953
        @boundscheck checkbounds(dest, i:(i + length(src) - 1))
×
954
        for x in src
×
955
            @inbounds dest[i] = x
×
956
            i += 1
×
957
        end
×
958
    else
959
        for x in src
×
960
            dest[i] = x
×
961
            i += 1
×
962
        end
×
963
    end
964
    return dest
×
965
end
966

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

996
# this method must be separate from the above since src might not have a length
997
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
46✔
998
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
46✔
999
        ", elements, but n should be non-negative")))
1000
    n == 0 && return dest
46✔
1001
    dmax = dstart + n - 1
46✔
1002
    inds = LinearIndices(dest)
46✔
1003
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
92✔
1004
        sstart < 1 && throw(ArgumentError(LazyString("source start offset (",
×
1005
            sstart,") is < 1")))
1006
        throw(BoundsError(dest, dstart:dmax))
×
1007
    end
1008
    y = iterate(src)
46✔
1009
    for j = 1:(sstart-1)
46✔
1010
        if y === nothing
×
1011
            throw(ArgumentError(LazyString(
×
1012
                "source has fewer elements than required, ",
1013
                "expected at least ",sstart,", got ",j-1)))
1014
        end
1015
        y = iterate(src, y[2])
×
1016
    end
×
1017
    if y === nothing
46✔
1018
        throw(ArgumentError(LazyString(
×
1019
            "source has fewer elements than required, ",
1020
            "expected at least ",sstart," got ", sstart-1)))
1021
    end
1022
    val, st = y
×
1023
    i = Int(dstart)
×
1024
    @inbounds dest[i] = val
46✔
1025
    for val in Iterators.take(Iterators.rest(src, st), n-1)
92✔
1026
        i += 1
92✔
1027
        @inbounds dest[i] = val
92✔
1028
    end
138✔
1029
    i < dmax && throw(BoundsError(dest, i))
46✔
1030
    return dest
46✔
1031
end
1032

1033
## copy between abstract arrays - generally more efficient
1034
## since a single index variable can be used.
1035

1036
"""
1037
    copyto!(dest::AbstractArray, src) -> dest
1038

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

1043
See also [`copy!`](@ref Base.copy!), [`copy`](@ref).
1044

1045
$(_DOCS_ALIASING_WARNING)
1046

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

1051
julia> y = zeros(7);
1052

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

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

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

1082
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
×
1083
    isempty(src) && return dest
×
1084
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
×
1085
    idf, isf = first(destinds), first(srcinds)
×
1086
    Δi = idf - isf
×
1087
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
×
1088
        throw(BoundsError(dest, srcinds))
1089
    if deststyle isa IndexLinear
×
1090
        if srcstyle isa IndexLinear
×
1091
            # Single-index implementation
1092
            @inbounds for i in srcinds
×
1093
                dest[i + Δi] = src[i]
×
1094
            end
×
1095
        else
1096
            # Dual-index implementation
1097
            i = idf - 1
×
1098
            @inbounds for a in src
×
1099
                dest[i+=1] = a
×
1100
            end
×
1101
        end
1102
    else
1103
        iterdest, itersrc = eachindex(dest), eachindex(src)
×
1104
        if iterdest == itersrc
×
1105
            # Shared-iterator implementation
1106
            for I in iterdest
×
1107
                @inbounds dest[I] = src[I]
×
1108
            end
×
1109
        else
1110
            # Dual-iterator implementation
1111
            for (Idest, Isrc) in zip(iterdest, itersrc)
×
1112
                @inbounds dest[Idest] = src[Isrc]
×
1113
            end
×
1114
        end
1115
    end
1116
    return dest
×
1117
end
1118

1119
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
×
1120
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
×
1121
end
1122

1123
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray, sstart::Integer)
×
1124
    srcinds = LinearIndices(src)
×
1125
    checkbounds(Bool, srcinds, sstart) || throw(BoundsError(src, sstart))
×
1126
    copyto!(dest, dstart, src, sstart, last(srcinds)-sstart+1)
×
1127
end
1128

1129
function copyto!(dest::AbstractArray, dstart::Integer,
372,024✔
1130
                 src::AbstractArray, sstart::Integer,
1131
                 n::Integer)
1132
    n == 0 && return dest
372,024✔
1133
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
372,024✔
1134
        n," elements, but n should be non-negative")))
1135
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
372,024✔
1136
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
372,024✔
1137
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
372,024✔
1138
    src′ = unalias(dest, src)
372,024✔
1139
    @inbounds for i = 0:n-1
372,024✔
1140
        dest[dstart+i] = src′[sstart+i]
21,686,869✔
1141
    end
43,001,714✔
1142
    return dest
372,024✔
1143
end
1144

1145
function copy(a::AbstractArray)
×
1146
    @_propagate_inbounds_meta
×
1147
    copymutable(a)
6,281✔
1148
end
1149

1150
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
×
1151
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1152
    if length(ir_dest) != length(ir_src)
×
1153
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1154
            length(ir_src)," and ",length(ir_dest),")")))
1155
    end
1156
    if length(jr_dest) != length(jr_src)
×
1157
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1158
            length(jr_src)," and ",length(jr_dest),")")))
1159
    end
1160
    @boundscheck checkbounds(B, ir_dest, jr_dest)
×
1161
    @boundscheck checkbounds(A, ir_src, jr_src)
×
1162
    A′ = unalias(B, A)
×
1163
    jdest = first(jr_dest)
×
1164
    for jsrc in jr_src
×
1165
        idest = first(ir_dest)
×
1166
        for isrc in ir_src
×
1167
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
×
1168
            idest += step(ir_dest)
×
1169
        end
×
1170
        jdest += step(jr_dest)
×
1171
    end
×
1172
    return B
×
1173
end
1174

1175
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
2✔
1176

1177
function copyto_axcheck!(dest, src)
×
1178
    _checkaxs(axes(dest), axes(src))
125✔
1179
    copyto!(dest, src)
126✔
1180
end
1181

1182
"""
1183
    copymutable(a)
1184

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

1190
# Examples
1191
```jldoctest
1192
julia> tup = (1, 2, 3)
1193
(1, 2, 3)
1194

1195
julia> Base.copymutable(tup)
1196
3-element Vector{Int64}:
1197
 1
1198
 2
1199
 3
1200
```
1201
"""
1202
function copymutable(a::AbstractArray)
×
1203
    @_propagate_inbounds_meta
×
1204
    copyto!(similar(a), a)
7,879✔
1205
end
1206
copymutable(itr) = collect(itr)
×
1207

1208
zero(x::AbstractArray{T}) where {T<:Number} = fill!(similar(x, typeof(zero(T))), zero(T))
×
1209
zero(x::AbstractArray{S}) where {S<:Union{Missing, Number}} = fill!(similar(x, typeof(zero(S))), zero(S))
×
1210
zero(x::AbstractArray) = map(zero, x)
×
1211

1212
function _one(unit::T, mat::AbstractMatrix) where {T}
×
1213
    (rows, cols) = axes(mat)
×
1214
    (length(rows) == length(cols)) ||
×
1215
      throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
1216
    zer = zero(unit)::T
×
1217
    require_one_based_indexing(mat)
×
1218
    I = similar(mat, T)
×
1219
    fill!(I, zer)
×
1220
    for i ∈ rows
×
1221
        I[i, i] = unit
×
1222
    end
×
1223
    I
×
1224
end
1225

1226
one(x::AbstractMatrix{T}) where {T} = _one(one(T), x)
×
1227
oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
×
1228

1229
## iteration support for arrays by iterating over `eachindex` in the array ##
1230
# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1231

1232
# While the definitions for IndexLinear are all simple enough to inline on their
1233
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1234
# inlining.
1235
function iterate(A::AbstractArray, state=(eachindex(A),))
1236
    y = iterate(state...)
392,729✔
1237
    y === nothing && return nothing
132,006✔
1238
    A[y[1]], (state[1], tail(y)...)
131,850✔
1239
end
1240

1241
isempty(a::AbstractArray) = (length(a) == 0)
2,402,938✔
1242

1243

1244
## range conversions ##
1245

1246
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
×
1247
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
×
1248
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
×
1249
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
×
1250
    LinRange(T(r.start), T(r.stop), length(r))
×
1251
end
1252

1253
## unsafe/pointer conversions ##
1254

1255
# note: the following type definitions don't mean any AbstractArray is convertible to
1256
# a data Ref. they just map the array element type to the pointer type for
1257
# convenience in cases that work.
1258
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
942,704✔
1259
function pointer(x::AbstractArray{T}, i::Integer) where T
1260
    @inline
×
1261
    pointer(x) + Int(_memory_offset(x, i))::Int
244,600✔
1262
end
1263

1264
# The distance from pointer(x) to the element at x[I...] in bytes
1265
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
244,600✔
1266
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
×
1267
    J = _to_subscript_indices(x, I...)
×
1268
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
×
1269
end
1270

1271
## Special constprop heuristics for getindex/setindex
1272
typename(typeof(function getindex end)).constprop_heuristic = Core.ARRAY_INDEX_HEURISTIC
1273
typename(typeof(function setindex! end)).constprop_heuristic = Core.ARRAY_INDEX_HEURISTIC
1274

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

1287
Return a subset of array `A` as selected by the indices `inds`.
1288

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

1293
When `inds` selects multiple elements, this function returns a newly
1294
allocated array. To index multiple elements without making a copy,
1295
use [`view`](@ref) instead.
1296

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

1299
# Examples
1300
```jldoctest
1301
julia> A = [1 2; 3 4]
1302
2×2 Matrix{Int64}:
1303
 1  2
1304
 3  4
1305

1306
julia> getindex(A, 1)
1307
1
1308

1309
julia> getindex(A, [2, 1])
1310
2-element Vector{Int64}:
1311
 3
1312
 1
1313

1314
julia> getindex(A, 2:4)
1315
3-element Vector{Int64}:
1316
 3
1317
 2
1318
 4
1319

1320
julia> getindex(A, 2, 1)
1321
3
1322

1323
julia> getindex(A, CartesianIndex(2, 1))
1324
3
1325

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

1331
julia> getindex(A, 2, :)
1332
2-element Vector{Int64}:
1333
 3
1334
 4
1335

1336
julia> getindex(A, A .> 2)
1337
2-element Vector{Int64}:
1338
 3
1339
 4
1340
```
1341
"""
1342
function getindex(A::AbstractArray, I...)
2✔
1343
    @_propagate_inbounds_meta
2✔
1344
    error_if_canonical_getindex(IndexStyle(A), A, I...)
2✔
1345
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
22,749,016✔
1346
end
1347
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1348
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
16,177✔
1349

1350
@inline unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
×
1351

1352
struct CanonicalIndexError <: Exception
1353
    func::String
1354
    type::Any
1355
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
×
1356
end
1357

1358
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
×
1359
    throw(CanonicalIndexError("getindex", typeof(A)))
1360
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
×
1361
    throw(CanonicalIndexError("getindex", typeof(A)))
1362
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
2✔
1363

1364
## Internal definitions
1365
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1366
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1367

1368
## IndexLinear Scalar indexing: canonical method is one Int
1369
_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)
22,210,457✔
1370
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
×
1371
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
1372
    @inline
×
1373
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
526,838✔
1374
    @inbounds r = getindex(A, _to_linear_index(A, I...))
526,838✔
1375
    r
×
1376
end
1377
_to_linear_index(A::AbstractArray, i::Integer) = i
×
1378
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
4✔
1379
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
×
1380
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
636,414✔
1381

1382
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1383
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
×
1384
    @inline
×
1385
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
×
1386
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
×
1387
    r
×
1388
end
1389
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
×
1390
    @_propagate_inbounds_meta
×
1391
    getindex(A, I...)
×
1392
end
1393
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
×
1394
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
×
1395
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1396
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
×
1397
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1398
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
×
1399
    @inline
×
1400
    J, Jrem = IteratorsMD.split(I, Val(N))
×
1401
    _to_subscript_indices(A, J, Jrem)
×
1402
end
1403
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
×
1404
    __to_subscript_indices(A, axes(A), J, Jrem)
1405
function __to_subscript_indices(A::AbstractArray,
×
1406
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1407
    @inline
×
1408
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
×
1409
end
1410
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
×
1411
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
×
1412
_remaining_size(::Tuple{Any}, t::Tuple) = t
×
1413
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
×
1414
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1415
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
×
1416

1417
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1418
# function that allows dispatch on array storage
1419

1420
"""
1421
    setindex!(A, X, inds...)
1422
    A[inds...] = X
1423

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

1427
$(_DOCS_ALIASING_WARNING)
1428

1429
# Examples
1430
```jldoctest
1431
julia> A = zeros(2,2);
1432

1433
julia> setindex!(A, [10, 20], [1, 2]);
1434

1435
julia> A[[3, 4]] = [30, 40];
1436

1437
julia> A
1438
2×2 Matrix{Float64}:
1439
 10.0  30.0
1440
 20.0  40.0
1441
```
1442
"""
1443
function setindex!(A::AbstractArray, v, I...)
1444
    @_propagate_inbounds_meta
×
1445
    error_if_canonical_setindex(IndexStyle(A), A, I...)
×
1446
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
638,347✔
1447
end
1448
function unsafe_setindex!(A::AbstractArray, v, I...)
×
1449
    @inline
×
1450
    @inbounds r = setindex!(A, v, I...)
×
1451
    r
×
1452
end
1453

1454
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
×
1455
    throw(CanonicalIndexError("setindex!", typeof(A)))
1456
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
×
1457
    throw(CanonicalIndexError("setindex!", typeof(A)))
1458
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
×
1459

1460
## Internal definitions
1461
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1462
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1463

1464
## IndexLinear Scalar indexing
1465
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
525,965✔
1466
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
1467
    @inline
×
1468
    @boundscheck checkbounds(A, I...)
112,382✔
1469
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
112,382✔
1470
    r
×
1471
end
1472

1473
# IndexCartesian Scalar indexing
1474
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
×
1475
    @_propagate_inbounds_meta
×
1476
    setindex!(A, v, I...)
×
1477
end
1478
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
×
1479
    @inline
×
1480
    @boundscheck checkbounds(A, I...)
×
1481
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
×
1482
    r
×
1483
end
1484

1485
_unsetindex!(A::AbstractArray, i::Integer) = _unsetindex!(A, to_index(i))
×
1486

1487
"""
1488
    parent(A)
1489

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

1495
# Examples
1496
```jldoctest
1497
julia> A = [1 2; 3 4]
1498
2×2 Matrix{Int64}:
1499
 1  2
1500
 3  4
1501

1502
julia> V = view(A, 1:2, :)
1503
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1504
 1  2
1505
 3  4
1506

1507
julia> parent(V)
1508
2×2 Matrix{Int64}:
1509
 1  2
1510
 3  4
1511
```
1512
"""
1513
function parent end
1514

1515
parent(a::AbstractArray) = a
×
1516

1517
## rudimentary aliasing detection ##
1518
"""
1519
    Base.unalias(dest, A)
1520

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

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

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

1531
See also [`Base.mightalias`](@ref).
1532
"""
1533
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
372,376✔
1534
unalias(dest, A::AbstractRange) = A
1✔
1535
unalias(dest, A) = A
1✔
1536

1537
"""
1538
    Base.unaliascopy(A)
1539

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

1543
This must return an object of the same type as `A` to preserve optimal performance in the
1544
much more common case where aliasing does not occur. By default,
1545
`unaliascopy(A::AbstractArray)` will attempt to use [`copy(A)`](@ref), but in cases where
1546
`copy(A)` is not a `typeof(A)`, then the array should provide a custom implementation of
1547
`Base.unaliascopy(A)`.
1548
"""
1549
unaliascopy(A::Array) = copy(A)
×
1550
unaliascopy(A::AbstractArray)::typeof(A) = (@noinline; _unaliascopy(A, copy(A)))
×
1551
_unaliascopy(A::T, C::T) where {T} = C
×
1552
function _unaliascopy(A, C)
×
1553
    Aw = typename(typeof(A)).wrapper
×
1554
    throw(ArgumentError(LazyString("an array of type `", Aw, "` shares memory with another argument ",
×
1555
    "and must make a preventative copy of itself in order to maintain consistent semantics, ",
1556
    "but `copy(::", typeof(A), ")` returns a new array of type `", typeof(C), "`.\n",
1557
    """To fix, implement:
1558
        `Base.unaliascopy(A::""", Aw, ")::typeof(A)`")))
1559
end
1560
unaliascopy(A) = A
×
1561

1562
"""
1563
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1564

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

1567
By default, this simply checks if either of the arrays reference the same memory
1568
regions, as identified by their [`Base.dataids`](@ref).
1569
"""
1570
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B))
372,376✔
1571
mightalias(x, y) = false
×
1572

1573
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1574
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1575
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1576
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1577
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
372,302✔
1578
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
×
1579
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1580
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
×
1581
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
×
1582

1583
"""
1584
    Base.dataids(A::AbstractArray)
1585

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

1588
Custom arrays that would like to opt-in to aliasing detection of their component
1589
parts can specialize this method to return the concatenation of the `dataids` of
1590
their component parts.  A typical definition for an array that wraps a parent is
1591
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1592
"""
1593
dataids(A::AbstractArray) = (UInt(objectid(A)),)
38✔
1594
dataids(A::Memory) = (UInt(A.ptr),)
744,566✔
1595
dataids(A::Array) = dataids(A.ref.mem)
744,372✔
1596
dataids(::AbstractRange) = ()
×
1597
dataids(x) = ()
×
1598

1599
## get (getindex with a default value) ##
1600

1601
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1602
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1603

1604
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
4✔
1605
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
×
1606
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
×
1607
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
×
1608
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
×
1609
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
×
1610

1611
function get!(X::AbstractVector{T}, A::AbstractVector, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
×
1612
    # 1d is not linear indexing
1613
    ind = findall(in(axes1(A)), I)
×
1614
    X[ind] = A[I[ind]]
×
1615
    Xind = axes1(X)
×
1616
    X[first(Xind):first(ind)-1] = default
×
1617
    X[last(ind)+1:last(Xind)] = default
×
1618
    X
×
1619
end
1620
function get!(X::AbstractArray{T}, A::AbstractArray, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
×
1621
    # Linear indexing
1622
    ind = findall(in(1:length(A)), I)
×
1623
    X[ind] = A[I[ind]]
×
1624
    fill!(view(X, 1:first(ind)-1), default)
×
1625
    fill!(view(X, last(ind)+1:length(X)), default)
×
1626
    X
×
1627
end
1628

1629
get(A::AbstractArray, I::AbstractRange, default) = get!(similar(A, typeof(default), index_shape(I)), A, I, default)
×
1630

1631
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
×
1632
    fill!(X, default)
×
1633
    dst, src = indcopy(size(A), I)
×
1634
    X[dst...] = A[src...]
×
1635
    X
×
1636
end
1637

1638
get(A::AbstractArray, I::RangeVecIntList, default) =
×
1639
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1640

1641
## structured matrix methods ##
1642
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
×
1643
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
×
1644

1645
## Concatenation ##
1646
eltypeof(x) = typeof(x)
1✔
1647
eltypeof(x::AbstractArray) = eltype(x)
3✔
1648

1649
promote_eltypeof() = error()
×
1650
promote_eltypeof(v1) = eltypeof(v1)
×
1651
promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2))
2✔
1652
promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...))
×
1653
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
×
1654
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
×
1655

1656
promote_eltype() = error()
×
1657
promote_eltype(v1) = eltype(v1)
×
1658
promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2))
×
1659
promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...))
×
1660
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
×
1661
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
6✔
1662

1663
#TODO: ERROR CHECK
1664
_cat(catdim::Int) = Vector{Any}()
×
1665

1666
typed_vcat(::Type{T}) where {T} = Vector{T}()
×
1667
typed_hcat(::Type{T}) where {T} = Vector{T}()
×
1668

1669
## cat: special cases
1670
vcat(X::T...) where {T}         = T[ X[i] for i=eachindex(X) ]
×
1671
vcat(X::T...) where {T<:Number} = T[ X[i] for i=eachindex(X) ]
×
1672
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=eachindex(X) ]
×
1673
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=eachindex(X) ]
×
1674

1675
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
×
1676
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
×
1677
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
×
1678
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
×
1679

1680
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
×
1681
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
×
1682

1683
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1684
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1685
# but that solution currently fails (see #27188 and #27224)
1686
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1687

1688
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
2✔
1689
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
3✔
1690
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1691

1692
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
1693
    pos = 1
1✔
1694
    for k=1:Int(length(V))::Int
2✔
1695
        Vk = V[k]
80✔
1696
        p1 = pos + Int(length(Vk))::Int - 1
80✔
1697
        a[pos:p1] = Vk
99✔
1698
        pos = p1+1
80✔
1699
    end
81✔
1700
    a
1✔
1701
end
1702

1703
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
×
1704

1705
# Catch indexing errors like v[i +1] (instead of v[i+1] or v[i + 1]), where indexing is
1706
# interpreted as a typed concatenation. (issue #49676)
1707
typed_hcat(::AbstractArray, other...) = throw(ArgumentError("It is unclear whether you \
×
1708
    intend to perform an indexing operation or typed concatenation. If you intend to \
1709
    perform indexing (v[1 + 2]), adjust spacing or insert missing operator to clarify. \
1710
    If you intend to perform typed concatenation (T[1 2]), ensure that T is a type."))
1711

1712

1713
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
×
1714
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
×
1715

1716
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
×
1717
    nargs = length(A)
×
1718
    nrows = size(A[1], 1)
×
1719
    ncols = 0
×
1720
    dense = true
×
1721
    for j = 1:nargs
×
1722
        Aj = A[j]
×
1723
        if size(Aj, 1) != nrows
×
1724
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
×
1725
        end
1726
        dense &= isa(Aj,Array)
×
1727
        nd = ndims(Aj)
×
1728
        ncols += (nd==2 ? size(Aj,2) : 1)
×
1729
    end
×
1730
    B = similar(A[1], T, nrows, ncols)
×
1731
    pos = 1
×
1732
    if dense
×
1733
        for k=1:nargs
×
1734
            Ak = A[k]
×
1735
            n = length(Ak)
×
1736
            copyto!(B, pos, Ak, 1, n)
×
1737
            pos += n
×
1738
        end
×
1739
    else
1740
        for k=1:nargs
×
1741
            Ak = A[k]
×
1742
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
×
1743
            B[:, pos:p1] = Ak
×
1744
            pos = p1+1
×
1745
        end
×
1746
    end
1747
    return B
×
1748
end
1749

1750
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
×
1751
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
×
1752

1753
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
×
1754
    nargs = length(A)
×
1755
    nrows = sum(a->size(a, 1), A)::Int
×
1756
    ncols = size(A[1], 2)
×
1757
    for j = 2:nargs
×
1758
        if size(A[j], 2) != ncols
×
1759
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
×
1760
        end
1761
    end
×
1762
    B = similar(A[1], T, nrows, ncols)
×
1763
    pos = 1
×
1764
    for k=1:nargs
×
1765
        Ak = A[k]
×
1766
        p1 = pos+size(Ak,1)::Int-1
×
1767
        B[pos:p1, :] = Ak
×
1768
        pos = p1+1
×
1769
    end
×
1770
    return B
×
1771
end
1772

1773
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
2✔
1774

1775
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
1✔
1776
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1777

1778
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
×
1779
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1780

1781
## cat: general case
1782

1783
# helper functions
1784
cat_size(A) = (1,)
1✔
1785
cat_size(A::AbstractArray) = size(A)
3✔
1786
cat_size(A, d) = 1
×
1787
cat_size(A::AbstractArray, d) = size(A, d)
3✔
1788

1789
cat_length(::Any) = 1
×
1790
cat_length(a::AbstractArray) = length(a)
×
1791

1792
cat_ndims(a) = 0
×
1793
cat_ndims(a::AbstractArray) = ndims(a)
×
1794

1795
cat_indices(A, d) = OneTo(1)
1✔
1796
cat_indices(A::AbstractArray, d) = axes(A, d)
3✔
1797

1798
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1✔
1799
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
×
1800
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1✔
1801
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
×
1802
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
×
1803
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
×
1804

1805
# These are for backwards compatibility (even though internal)
1806
cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
×
1807
function cat_shape(dims, shapes::Tuple)
×
1808
    out_shape = ()
×
1809
    for s in shapes
×
1810
        out_shape = _cshp(1, dims, out_shape, s)
×
1811
    end
×
1812
    return out_shape
×
1813
end
1814
# The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1815
cat_size_shape(dims) = ntuple(zero, Val(length(dims)))
×
1816
@inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
2✔
1817
_cat_size_shape(dims, shape) = shape
×
1818
@inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
2✔
1819

1820
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1821
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
×
1822
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
×
1823
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
×
1824
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1825
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
2✔
1826
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1827
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
×
1828
    _cs(ndim, shape[1], 1)
×
1829
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
×
1830
end
1831
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
×
1832
    next = _cs(ndim, shape[1], nshape[1])
×
1833
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
×
1834
end
1835
@inline function _cshp(ndim::Int, dims, shape, nshape)
1836
    a = shape[1]
2✔
1837
    b = nshape[1]
2✔
1838
    next = dims[1] ? a + b : _cs(ndim, a, b)
2✔
1839
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
2✔
1840
end
1841

1842
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
×
1843
    "mismatch in dimension $d (expected $a got $b)")))
1844

1845
dims2cat(::Val{dims}) where dims = dims2cat(dims)
×
1846
function dims2cat(dims)
×
1847
    if any(≤(0), dims)
×
1848
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
×
1849
    end
1850
    ntuple(in(dims), maximum(dims))
×
1851
end
1852

1853
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
3✔
1854

1855
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
1856
    catdims = dims2cat(dims)
2✔
1857
    shape = cat_size_shape(catdims, X...)
2✔
1858
    A = cat_similar(X[1], T, shape)
2✔
1859
    if count(!iszero, catdims)::Int > 1
2✔
1860
        fill!(A, zero(T))
×
1861
    end
1862
    return __cat(A, shape, catdims, X...)
3✔
1863
end
1864
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1865
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1866
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1867

1868
# Why isn't this called `__cat!`?
1869
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
3✔
1870

1871
function __cat_offset!(A, shape, catdims, offsets, x, X...)
1✔
1872
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1873
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
5✔
1874
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
5✔
1875
end
1876
__cat_offset!(A, shape, catdims, offsets) = A
2✔
1877

1878
function __cat_offset1!(A, shape, catdims, offsets, x)
1879
    inds = ntuple(length(offsets)) do i
5✔
1880
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
5✔
1881
    end
1882
    _copy_or_fill!(A, inds, x)
6✔
1883
    newoffsets = ntuple(length(offsets)) do i
4✔
1884
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
4✔
1885
    end
1886
    return newoffsets
4✔
1887
end
1888

1889
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
1✔
1890
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
5✔
1891

1892
"""
1893
    vcat(A...)
1894

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

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

1901
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1902

1903
# Examples
1904
```jldoctest
1905
julia> v = vcat([1,2], [3,4])
1906
4-element Vector{Int64}:
1907
 1
1908
 2
1909
 3
1910
 4
1911

1912
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1913
true
1914

1915
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1916
true
1917

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

1921
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1922
3-element Vector{Float64}:
1923
 1.0
1924
 1.5
1925
 2.0
1926

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

1930
julia> vcat(two...)
1931
3×3 Matrix{Float64}:
1932
 10.0  20.0  30.0
1933
  4.0   5.0   6.0
1934
  7.0   8.0   9.0
1935

1936
julia> vs = [[1, 2], [3, 4], [5, 6]];
1937

1938
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1939
6-element Vector{Int64}:
1940
 1
1941
 2
1942
 3
1943
 4
1944
 5
1945
 6
1946

1947
julia> ans == collect(Iterators.flatten(vs))
1948
true
1949
```
1950
"""
1951
vcat(X...) = cat(X...; dims=Val(1))
×
1952
"""
1953
    hcat(A...)
1954

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

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

1962
See also [`vcat`](@ref), [`hvcat`](@ref).
1963

1964
# Examples
1965
```jldoctest
1966
julia> hcat([1,2], [3,4], [5,6])
1967
2×3 Matrix{Int64}:
1968
 1  3  5
1969
 2  4  6
1970

1971
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1972
1×7 Matrix{Int64}:
1973
 1  2  30  40  5  6  7
1974

1975
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1976
true
1977

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

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

1984
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
1985
2×6 Matrix{Float64}:
1986
 0.0  0.0  1.0  2.0  50.0  60.0
1987
 0.0  0.0  3.0  4.0  70.0  80.0
1988

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

1992
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
1993
0×3 Matrix{Int64}
1994

1995
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
1996
2×1 Matrix{Any}:
1997
 1.1
1998
 9.9
1999
```
2000
"""
2001
hcat(X...) = cat(X...; dims=Val(2))
×
2002

2003
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
×
2004
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
×
2005

2006
"""
2007
    cat(A...; dims)
2008

2009
Concatenate the input arrays along the dimensions specified in `dims`.
2010

2011
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
2012
a in A)`.
2013
Along other dimensions, all input arrays should have the same size,
2014
which will also be the size of the output array along those dimensions.
2015

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

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

2025
The keyword also accepts `Val(dims)`.
2026

2027
!!! compat "Julia 1.8"
2028
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
2029

2030
# Examples
2031

2032
Concatenate two arrays in different dimensions:
2033
```jldoctest
2034
julia> a = [1 2 3]
2035
1×3 Matrix{Int64}:
2036
 1  2  3
2037

2038
julia> b = [4 5 6]
2039
1×3 Matrix{Int64}:
2040
 4  5  6
2041

2042
julia> cat(a, b; dims=1)
2043
2×3 Matrix{Int64}:
2044
 1  2  3
2045
 4  5  6
2046

2047
julia> cat(a, b; dims=2)
2048
1×6 Matrix{Int64}:
2049
 1  2  3  4  5  6
2050

2051
julia> cat(a, b; dims=(1, 2))
2052
2×6 Matrix{Int64}:
2053
 1  2  3  0  0  0
2054
 0  0  0  4  5  6
2055
```
2056

2057
# Extended Help
2058

2059
Concatenate 3D arrays:
2060
```jldoctest
2061
julia> a = ones(2, 2, 3);
2062

2063
julia> b = ones(2, 2, 4);
2064

2065
julia> c = cat(a, b; dims=3);
2066

2067
julia> size(c) == (2, 2, 7)
2068
true
2069
```
2070

2071
Concatenate arrays of different sizes:
2072
```jldoctest
2073
julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2)  # same as hcat
2074
2×6×1 Array{Float64, 3}:
2075
[:, :, 1] =
2076
 1.0  2.0  3.14159  10.0  10.0  10.0
2077
 3.0  4.0  3.14159  10.0  10.0  10.0
2078
```
2079

2080
Construct a block diagonal matrix:
2081
```
2082
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
2083
4×7 Matrix{Bool}:
2084
 1  0  0  0  0  0  0
2085
 0  1  1  0  0  0  0
2086
 0  1  1  0  0  0  0
2087
 0  0  0  1  1  1  1
2088
```
2089

2090
```
2091
julia> cat(1, [2], [3;;]; dims=Val(2))
2092
1×3 Matrix{Int64}:
2093
 1  2  3
2094
```
2095

2096
!!! note
2097
    `cat` does not join two strings, you may want to use `*`.
2098

2099
```jldoctest
2100
julia> a = "aaa";
2101

2102
julia> b = "bbb";
2103

2104
julia> cat(a, b; dims=1)
2105
2-element Vector{String}:
2106
 "aaa"
2107
 "bbb"
2108

2109
julia> cat(a, b; dims=2)
2110
1×2 Matrix{String}:
2111
 "aaa"  "bbb"
2112

2113
julia> a * b
2114
"aaabbb"
2115
```
2116
"""
2117
@inline cat(A...; dims) = _cat(dims, A...)
5✔
2118
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
2119
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
×
2120

2121
# The specializations for 1 and 2 inputs are important
2122
# especially when running with --inline=no, see #11158
2123
vcat(A::AbstractArray) = cat(A; dims=Val(1))
×
2124
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
×
2125
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
2126
vcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(1))
1✔
2127
hcat(A::AbstractArray) = cat(A; dims=Val(2))
×
2128
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
×
2129
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
×
2130
hcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(2))
×
2131

2132
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
×
2133
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
×
2134
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
×
2135
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
×
2136
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
×
2137
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
×
2138

2139
# 2d horizontal and vertical concatenation
2140

2141
# these are produced in lowering if splatting occurs inside hvcat
2142
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
×
2143
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
×
2144

2145
function hvcat(nbc::Int, as...)
×
2146
    # nbc = # of block columns
2147
    n = length(as)
×
2148
    mod(n,nbc) != 0 &&
×
2149
        throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
2150
    nbr = div(n,nbc)
×
2151
    hvcat(ntuple(Returns(nbc), nbr), as...)
×
2152
end
2153

2154
"""
2155
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2156

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

2162
# Examples
2163
```jldoctest
2164
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2165
(1, 2, 3, 4, 5, 6)
2166

2167
julia> [a b c; d e f]
2168
2×3 Matrix{Int64}:
2169
 1  2  3
2170
 4  5  6
2171

2172
julia> hvcat((3,3), a,b,c,d,e,f)
2173
2×3 Matrix{Int64}:
2174
 1  2  3
2175
 4  5  6
2176

2177
julia> [a b; c d; e f]
2178
3×2 Matrix{Int64}:
2179
 1  2
2180
 3  4
2181
 5  6
2182

2183
julia> hvcat((2,2,2), a,b,c,d,e,f)
2184
3×2 Matrix{Int64}:
2185
 1  2
2186
 3  4
2187
 5  6
2188
julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f)
2189
true
2190
```
2191
"""
2192
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
×
2193
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray{T}...) where {T} = typed_hvcat(T, rows, xs...)
×
2194

2195
rows_to_dimshape(rows::Tuple{Vararg{Int}}) = all(==(rows[1]), rows) ? (length(rows), rows[1]) : (rows, (sum(rows),))
×
2196
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T = typed_hvncat(T, rows_to_dimshape(rows), true, as...)
×
2197

2198
hvcat(rows::Tuple{Vararg{Int}}) = []
×
2199
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2200

2201
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
×
2202
    nr = length(rows)
×
2203
    nc = rows[1]
×
2204

2205
    a = Matrix{T}(undef, nr, nc)
×
2206
    if length(a) != length(xs)
×
2207
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
×
2208
    end
2209
    k = 1
×
2210
    @inbounds for i=1:nr
×
2211
        if nc != rows[i]
×
2212
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
×
2213
        end
2214
        for j=1:nc
×
2215
            a[i,j] = xs[k]
×
2216
            k += 1
×
2217
        end
×
2218
    end
×
2219
    a
×
2220
end
2221

2222
function hvcat_fill!(a::Array, xs::Tuple)
×
2223
    nr, nc = size(a,1), size(a,2)
×
2224
    len = length(xs)
×
2225
    if nr*nc != len
×
2226
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
×
2227
    end
2228
    k = 1
×
2229
    for i=1:nr
×
2230
        @inbounds for j=1:nc
×
2231
            a[i,j] = xs[k]
×
2232
            k += 1
×
2233
        end
×
2234
    end
×
2235
    a
×
2236
end
2237

2238
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
×
2239
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
×
2240
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2241
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
×
2242

2243
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
×
2244
    nr = length(rows)
×
2245
    nc = rows[1]
×
2246
    for i = 2:nr
×
2247
        if nc != rows[i]
×
2248
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
×
2249
        end
2250
    end
×
2251
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
×
2252
end
2253

2254
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T = typed_hvncat(T, rows_to_dimshape(rows), true, as...)
×
2255

2256
## N-dimensional concatenation ##
2257

2258
"""
2259
    hvncat(dim::Int, row_first, values...)
2260
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2261
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2262

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

2265
This function is called for block matrix syntax. The first argument either specifies the
2266
shape of the concatenation, similar to `hvcat`, as a tuple of tuples, or the dimensions that
2267
specify the key number of elements along each axis, and is used to determine the output
2268
dimensions. The `dims` form is more performant, and is used by default when the concatenation
2269
operation has the same number of elements along each axis (e.g., [a b; c d;;; e f ; g h]).
2270
The `shape` form is used when the number of elements along each axis is unbalanced
2271
(e.g., [a b ; c]). Unbalanced syntax needs additional validation overhead. The `dim` form
2272
is an optimization for concatenation along just one dimension. `row_first` indicates how
2273
`values` are ordered. The meaning of the first and second elements of `shape` are also
2274
swapped based on `row_first`.
2275

2276
# Examples
2277
```jldoctest
2278
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2279
(1, 2, 3, 4, 5, 6)
2280

2281
julia> [a b c;;; d e f]
2282
1×3×2 Array{Int64, 3}:
2283
[:, :, 1] =
2284
 1  2  3
2285

2286
[:, :, 2] =
2287
 4  5  6
2288

2289
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2290
2×1×3 Array{Int64, 3}:
2291
[:, :, 1] =
2292
 1
2293
 2
2294

2295
[:, :, 2] =
2296
 3
2297
 4
2298

2299
[:, :, 3] =
2300
 5
2301
 6
2302

2303
julia> [a b;;; c d;;; e f]
2304
1×2×3 Array{Int64, 3}:
2305
[:, :, 1] =
2306
 1  2
2307

2308
[:, :, 2] =
2309
 3  4
2310

2311
[:, :, 3] =
2312
 5  6
2313

2314
julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2315
1×3×2 Array{Int64, 3}:
2316
[:, :, 1] =
2317
 1  2  3
2318

2319
[:, :, 2] =
2320
 4  5  6
2321
```
2322

2323
# Examples for construction of the arguments
2324
```
2325
[a b c ; d e f ;;;
2326
 g h i ; j k l ;;;
2327
 m n o ; p q r ;;;
2328
 s t u ; v w x]
2329
⇒ dims = (2, 3, 4)
2330

2331
[a b ; c ;;; d ;;;;]
2332
 ___   _     _
2333
 2     1     1 = elements in each row (2, 1, 1)
2334
 _______     _
2335
 3           1 = elements in each column (3, 1)
2336
 _____________
2337
 4             = elements in each 3d slice (4,)
2338
 _____________
2339
 4             = elements in each 4d slice (4,)
2340
⇒ shape = ((2, 1, 1), (3, 1), (4,), (4,)) with `row_first` = true
2341
```
2342
"""
2343
hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...)
×
2344
hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...)
×
2345

2346
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
×
2347
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
×
2348
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
×
2349
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2350
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2351
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
×
2352

2353

2354
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
×
2355
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
×
2356

2357
# 1-dimensional hvncat methods
2358

2359
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
×
2360
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2361
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
×
2362
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
×
2363
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2364
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
×
2365
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2366

2367
_typed_hvncat_0d_only_one() =
×
2368
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2369

2370
# `@constprop :aggressive` here to form constant `Val(dim)` type to get type stability
2371
@constprop :aggressive _typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters
×
2372

2373
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
×
2374
    N < 0 &&
×
2375
        throw(ArgumentError("concatenation dimension must be non-negative"))
2376
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
×
2377
end
2378

2379
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
×
2380
    N < 0 &&
×
2381
        throw(ArgumentError("concatenation dimension must be non-negative"))
2382
    A = cat_similar(xs[1], T, (ntuple(x -> 1, Val(N - 1))..., length(xs)))
×
2383
    hvncat_fill!(A, false, xs)
×
2384
    return A
×
2385
end
2386

2387
function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
×
2388
    # optimization for arrays that can be concatenated by copying them linearly into the destination
2389
    # conditions: the elements must all have 1-length dimensions above N
2390
    length(as) > 0 ||
×
2391
        throw(ArgumentError("must have at least one element"))
2392
    N < 0 &&
×
2393
        throw(ArgumentError("concatenation dimension must be non-negative"))
2394
    for a ∈ as
×
2395
        ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) ||
×
2396
            return _typed_hvncat(T, (ntuple(x -> 1, Val(N - 1))..., length(as), 1), false, as...)
×
2397
            # the extra 1 is to avoid an infinite cycle
2398
    end
×
2399

2400
    nd = N
×
2401

2402
    Ndim = 0
×
2403
    for i ∈ eachindex(as)
×
2404
        Ndim += cat_size(as[i], N)
×
2405
        nd = max(nd, cat_ndims(as[i]))
×
2406
        for d ∈ 1:N - 1
×
2407
            cat_size(as[1], d) == cat_size(as[i], d) || throw(DimensionMismatch("mismatched size along axis $d in element $i"))
×
2408
        end
×
2409
    end
×
2410

2411
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
×
2412
    k = 1
×
2413
    for a ∈ as
×
2414
        for i ∈ eachindex(a)
×
2415
            A[k] = a[i]
×
2416
            k += 1
×
2417
        end
×
2418
    end
×
2419
    return A
×
2420
end
2421

2422
function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
×
2423
    length(as) > 0 ||
×
2424
        throw(ArgumentError("must have at least one element"))
2425
    N < 0 &&
×
2426
        throw(ArgumentError("concatenation dimension must be non-negative"))
2427
    nd = N
×
2428
    Ndim = 0
×
2429
    for i ∈ eachindex(as)
×
2430
        Ndim += cat_size(as[i], N)
×
2431
        nd = max(nd, cat_ndims(as[i]))
×
2432
        for d ∈ 1:N-1
×
2433
            cat_size(as[i], d) == 1 ||
×
2434
                throw(DimensionMismatch("all dimensions of element $i other than $N must be of length 1"))
2435
        end
×
2436
    end
×
2437

2438
    A = Array{T, nd}(undef, ntuple(x -> 1, Val(N - 1))..., Ndim, ntuple(x -> 1, nd - N)...)
×
2439

2440
    k = 1
×
2441
    for a ∈ as
×
2442
        if a isa AbstractArray
×
2443
            lena = length(a)
×
2444
            copyto!(A, k, a, 1, lena)
×
2445
            k += lena
×
2446
        else
2447
            A[k] = a
×
2448
            k += 1
×
2449
        end
2450
    end
×
2451
    return A
×
2452
end
2453

2454
# 0-dimensional cases for balanced and unbalanced hvncat method
2455

2456
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
×
2457
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
×
2458

2459

2460
# balanced dimensions hvncat methods
2461

2462
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
×
2463
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as::Number...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
×
2464

2465
function _typed_hvncat_1d(::Type{T}, ds::Int, ::Val{row_first}, as...) where {T, row_first}
×
2466
    lengthas = length(as)
×
2467
    ds > 0 ||
×
2468
        throw(ArgumentError("`dimsshape` argument must consist of positive integers"))
2469
    lengthas == ds ||
×
2470
        throw(ArgumentError("number of elements does not match `dimshape` argument; expected $ds, got $lengthas"))
2471
    if row_first
×
2472
        return _typed_hvncat(T, Val(2), as...)
×
2473
    else
2474
        return _typed_hvncat(T, Val(1), as...)
×
2475
    end
2476
end
2477

2478
function _typed_hvncat(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, xs::Number...) where {T, N}
×
2479
    all(>(0), dims) ||
×
2480
        throw(ArgumentError("`dims` argument must contain positive integers"))
2481
    A = Array{T, N}(undef, dims...)
×
2482
    lengtha = length(A)  # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations
×
2483
    lengthx = length(xs) # Cuts from 3 allocations to 1.
×
2484
    if lengtha != lengthx
×
2485
       throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)"))
×
2486
    end
2487
    hvncat_fill!(A, row_first, xs)
×
2488
    return A
×
2489
end
2490

2491
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
×
2492
    nr, nc = size(A, 1), size(A, 2)
×
2493
    na = prod(size(A)[3:end])
×
2494
    len = length(xs)
×
2495
    nrc = nr * nc
×
2496
    if nrc * na != len
×
2497
        throw(ArgumentError("argument count $(len) does not match specified shape $(size(A))"))
×
2498
    end
2499
    # putting these in separate functions leads to unnecessary allocations
2500
    if row_first
×
2501
        k = 1
×
2502
        for d ∈ 1:na
×
2503
            dd = nrc * (d - 1)
×
2504
            for i ∈ 1:nr
×
2505
                Ai = dd + i
×
2506
                for j ∈ 1:nc
×
2507
                    @inbounds A[Ai] = xs[k]
×
2508
                    k += 1
×
2509
                    Ai += nr
×
2510
                end
×
2511
            end
×
2512
        end
×
2513
    else
2514
        for k ∈ eachindex(xs)
×
2515
            @inbounds A[k] = xs[k]
×
2516
        end
×
2517
    end
2518
end
2519

2520
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
×
2521
    # function barrier after calculating the max is necessary for high performance
2522
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
×
2523
    return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
×
2524
end
2525

2526
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
×
2527
    length(as) > 0 ||
×
2528
        throw(ArgumentError("must have at least one element"))
2529
    all(>(0), dims) ||
×
2530
        throw(ArgumentError("`dims` argument must contain positive integers"))
2531

2532
    d1 = row_first ? 2 : 1
×
2533
    d2 = row_first ? 1 : 2
×
2534

2535
    outdims = zeros(Int, N)
×
2536

2537
    # validate shapes for lowest level of concatenation
2538
    d = findfirst(>(1), dims)
×
2539
    if d !== nothing # all dims are 1
×
2540
        if row_first && d < 3
×
2541
            d = d == 1 ? 2 : 1
×
2542
        end
2543
        nblocks = length(as) ÷ dims[d]
×
2544
        for b ∈ 1:nblocks
×
2545
            offset = ((b - 1) * dims[d])
×
2546
            startelementi = offset + 1
×
2547
            for i ∈ offset .+ (2:dims[d])
×
2548
                for dd ∈ 1:N
×
2549
                    dd == d && continue
×
2550
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
×
2551
                        throw(DimensionMismatch("incompatible shape in element $i"))
×
2552
                    end
2553
                end
×
2554
            end
×
2555
        end
×
2556
    end
2557

2558
    # discover number of rows or columns
2559
    for i ∈ 1:dims[d1]
×
2560
        outdims[d1] += cat_size(as[i], d1)
×
2561
    end
×
2562

2563
    currentdims = zeros(Int, N)
×
2564
    blockcount = 0
×
2565
    elementcount = 0
×
2566
    for i ∈ eachindex(as)
×
2567
        elementcount += cat_length(as[i])
×
2568
        currentdims[d1] += cat_size(as[i], d1)
×
2569
        if currentdims[d1] == outdims[d1]
×
2570
            currentdims[d1] = 0
×
2571
            for d ∈ (d2, 3:N...)
×
2572
                currentdims[d] += cat_size(as[i], d)
×
2573
                if outdims[d] == 0 # unfixed dimension
×
2574
                    blockcount += 1
×
2575
                    if blockcount == dims[d]
×
2576
                        outdims[d] = currentdims[d]
×
2577
                        currentdims[d] = 0
×
2578
                        blockcount = 0
×
2579
                    else
2580
                        break
×
2581
                    end
2582
                else # fixed dimension
2583
                    if currentdims[d] == outdims[d] # end of dimension
×
2584
                        currentdims[d] = 0
×
2585
                    elseif currentdims[d] < outdims[d] # dimension in progress
×
2586
                        break
×
2587
                    else # exceeded dimension
2588
                        throw(DimensionMismatch("argument $i has too many elements along axis $d"))
×
2589
                    end
2590
                end
2591
            end
×
2592
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
×
2593
            throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
×
2594
        end
2595
    end
×
2596

2597
    outlen = prod(outdims)
×
2598
    elementcount == outlen ||
×
2599
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2600

2601
    # copy into final array
2602
    A = cat_similar(as[1], T, ntuple(i -> outdims[i], N))
×
2603
    # @assert all(==(0), currentdims)
2604
    outdims .= 0
×
2605
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
×
2606
    return A
×
2607
end
2608

2609

2610
# unbalanced dimensions hvncat methods
2611

2612
function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
×
2613
    length(shape[1]) > 0 ||
×
2614
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2615
    return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
×
2616
end
2617

2618
function _typed_hvncat(T::Type, shape::NTuple{N, Tuple}, row_first::Bool, as...) where {N}
×
2619
    # function barrier after calculating the max is necessary for high performance
2620
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
×
2621
    return _typed_hvncat_shape(T, (shape..., ntuple(x -> shape[end], nd - N)...), row_first, as)
×
2622
end
2623

2624
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
×
2625
    length(as) > 0 ||
×
2626
        throw(ArgumentError("must have at least one element"))
2627
    all(>(0), tuple((shape...)...)) ||
×
2628
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2629

2630
    d1 = row_first ? 2 : 1
×
2631
    d2 = row_first ? 1 : 2
×
2632

2633
    shapev = collect(shape) # saves allocations later
×
2634
    all(!isempty, shapev) ||
×
2635
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2636
    length(shapev[end]) == 1 ||
×
2637
        throw(ArgumentError("last level of shape must contain only one integer"))
2638
    shapelength = shapev[end][1]
×
2639
    lengthas = length(as)
×
2640
    shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)"))
×
2641
    # discover dimensions
2642
    nd = max(N, cat_ndims(as[1]))
×
2643
    outdims = fill(-1, nd)
×
2644
    currentdims = zeros(Int, nd)
×
2645
    blockcounts = zeros(Int, nd)
×
2646
    shapepos = ones(Int, nd)
×
2647

2648
    elementcount = 0
×
2649
    for i ∈ eachindex(as)
×
2650
        elementcount += cat_length(as[i])
×
2651
        wasstartblock = false
×
2652
        for d ∈ 1:N
×
2653
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
×
2654
            dsize = cat_size(as[i], ad)
×
2655
            blockcounts[d] += 1
×
2656

2657
            if d == 1 || i == 1 || wasstartblock
×
2658
                currentdims[d] += dsize
×
2659
            elseif dsize != cat_size(as[i - 1], ad)
×
2660
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
×
2661
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2662
            end
2663

2664
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
×
2665

2666
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
×
2667
            if isendblock
×
2668
                if outdims[d] == -1
×
2669
                    outdims[d] = currentdims[d]
×
2670
                elseif outdims[d] != currentdims[d]
×
2671
                    throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
×
2672
                                             expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2673
                end
2674
                currentdims[d] = 0
×
2675
                blockcounts[d] = 0
×
2676
                shapepos[d] += 1
×
2677
                d > 1 && (blockcounts[d - 1] == 0 ||
×
2678
                    throw(DimensionMismatch("shape in level $d is inconsistent; level counts must nest \
2679
                                             evenly into each other")))
2680
            end
2681
        end
×
2682
    end
×
2683

2684
    outlen = prod(outdims)
×
2685
    elementcount == outlen ||
×
2686
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2687

2688
    if row_first
×
2689
        outdims[1], outdims[2] = outdims[2], outdims[1]
×
2690
    end
2691

2692
    # @assert all(==(0), currentdims)
2693
    # @assert all(==(0), blockcounts)
2694

2695
    # copy into final array
2696
    A = cat_similar(as[1], T, ntuple(i -> outdims[i], nd))
×
2697
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
×
2698
    return A
×
2699
end
2700

2701
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int},
×
2702
                              d1::Int, d2::Int, as::Tuple) where {T, N}
2703
    N > 1 || throw(ArgumentError("dimensions of the destination array must be at least 2"))
×
2704
    length(scratch1) == length(scratch2) == N ||
×
2705
        throw(ArgumentError("scratch vectors must have as many elements as the destination array has dimensions"))
2706
    0 < d1 < 3 &&
×
2707
    0 < d2 < 3 &&
2708
    d1 != d2 ||
2709
        throw(ArgumentError("d1 and d2 must be either 1 or 2, exclusive."))
2710
    outdims = size(A)
×
2711
    offsets = scratch1
×
2712
    inneroffsets = scratch2
×
2713
    for a ∈ as
×
2714
        if isa(a, AbstractArray)
×
2715
            for ai ∈ a
×
2716
                @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
×
2717
                A[Ai] = ai
×
2718

2719
                @inbounds for j ∈ 1:N
×
2720
                    inneroffsets[j] += 1
×
2721
                    inneroffsets[j] < cat_size(a, j) && break
×
2722
                    inneroffsets[j] = 0
×
2723
                end
×
2724
            end
×
2725
        else
2726
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
×
2727
            A[Ai] = a
×
2728
        end
2729

2730
        @inbounds for j ∈ (d1, d2, 3:N...)
×
2731
            offsets[j] += cat_size(a, j)
×
2732
            offsets[j] < outdims[j] && break
×
2733
            offsets[j] = 0
×
2734
        end
×
2735
    end
×
2736
end
2737

2738
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
×
2739
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2740
    Ai = inneroffsets[1] + offsets[1] + 1
×
2741
    for j ∈ 2:nd
×
2742
        increment = inneroffsets[j] + offsets[j]
×
2743
        for k ∈ 1:j-1
×
2744
            increment *= outdims[k]
×
2745
        end
×
2746
        Ai += increment
×
2747
    end
×
2748
    Ai
×
2749
end
2750

2751
"""
2752
    stack(iter; [dims])
2753

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

2757
By default the axes of the elements are placed first,
2758
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2759
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2760

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

2765
The various [`cat`](@ref) functions also combine arrays. However, these all
2766
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2767
the arrays along new dimensions.
2768
They also accept arrays as separate arguments, rather than a single collection.
2769

2770
!!! compat "Julia 1.9"
2771
    This function requires at least Julia 1.9.
2772

2773
# Examples
2774
```jldoctest
2775
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2776

2777
julia> mat = stack(vecs)
2778
2×3 Matrix{Float32}:
2779
 1.0  30.0  500.0
2780
 2.0  40.0  600.0
2781

2782
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2783
true
2784

2785
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2786
true
2787

2788
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2789
2×4 Matrix{Int64}:
2790
  1   2   3   4
2791
 10  11  12  13
2792

2793
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2794
true
2795

2796
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2797
3×2 Matrix{Float32}:
2798
   1.0    2.0
2799
  30.0   40.0
2800
 500.0  600.0
2801

2802
julia> x = rand(3,4);
2803

2804
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2805
true
2806
```
2807

2808
Higher-dimensional examples:
2809

2810
```jldoctest
2811
julia> A = rand(5, 7, 11);
2812

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

2815
julia> (element = size(first(E)), container = size(E))
2816
(element = (5, 11), container = (7,))
2817

2818
julia> stack(E) |> size
2819
(5, 11, 7)
2820

2821
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2822
true
2823

2824
julia> A == stack(E; dims=2)
2825
true
2826

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

2829
julia> (element = size(first(M)), container = size(M))
2830
(element = (2, 3), container = (5, 7))
2831

2832
julia> stack(M) |> size  # keeps all dimensions
2833
(2, 3, 5, 7)
2834

2835
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2836
(35, 2, 3)
2837

2838
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2839
(14, 15)
2840
```
2841
"""
2842
stack(iter; dims=:) = _stack(dims, iter)
×
2843

2844
"""
2845
    stack(f, args...; [dims])
2846

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

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

2854
See also [`mapslices`](@ref), [`eachcol`](@ref).
2855

2856
# Examples
2857
```jldoctest
2858
julia> stack(c -> (c, c-32), "julia")
2859
2×5 Matrix{Char}:
2860
 'j'  'u'  'l'  'i'  'a'
2861
 'J'  'U'  'L'  'I'  'A'
2862

2863
julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2864
         vcat(row, row .* n, row ./ n)
2865
       end
2866
2×9 Matrix{Float64}:
2867
 1.0  2.0  3.0   10.0   20.0   30.0  0.1   0.2   0.3
2868
 4.0  5.0  6.0  400.0  500.0  600.0  0.04  0.05  0.06
2869
```
2870
"""
2871
stack(f, iter; dims=:) = _stack(dims, f(x) for x in iter)
×
2872
stack(f, xs, yzs...; dims=:) = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
×
2873

2874
_stack(dims::Union{Integer, Colon}, iter) = _stack(dims, IteratorSize(iter), iter)
×
2875

2876
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
×
2877

2878
function _stack(dims, ::Union{HasShape, HasLength}, iter)
×
2879
    S = @default_eltype iter
×
2880
    T = S != Union{} ? eltype(S) : Any  # Union{} occurs for e.g. stack(1,2), postpone the error
×
2881
    if isconcretetype(T)
×
2882
        _typed_stack(dims, T, S, iter)
×
2883
    else  # Need to look inside, but shouldn't run an expensive iterator twice:
2884
        array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
×
2885
        isempty(array) && return _empty_stack(dims, T, S, iter)
×
2886
        T2 = mapreduce(eltype, promote_type, array)
×
2887
        _typed_stack(dims, T2, eltype(array), array)
×
2888
    end
2889
end
2890

2891
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
×
2892
    xit = iterate(A)
×
2893
    nothing === xit && return _empty_stack(:, T, S, A)
×
2894
    x1, _ = xit
×
2895
    ax1 = _iterator_axes(x1)
×
2896
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
×
2897
    off = firstindex(B)
×
2898
    len = length(x1)
×
2899
    while xit !== nothing
×
2900
        x, state = xit
×
2901
        _stack_size_check(x, ax1)
×
2902
        copyto!(B, off, x)
×
2903
        off += len
×
2904
        xit = iterate(A, state)
×
2905
    end
×
2906
    B
×
2907
end
2908

2909
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
×
2910
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
×
2911
_iterator_axes(x, ::IteratorSize) = axes(x)
×
2912

2913
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2914
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
×
2915
    _typed_stack(dims, T, S, IteratorSize(S), A)
2916
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
×
2917
    _typed_stack(dims, T, S, HasShape{1}(), A)
2918
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
×
2919
    if dims == N+1
×
2920
        _typed_stack(:, T, S, A, (_vec_axis(A),))
×
2921
    else
2922
        _dim_stack(dims, T, S, A)
×
2923
    end
2924
end
2925
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
×
2926
    _dim_stack(dims, T, S, A)
2927

2928
_vec_axis(A, ax=_iterator_axes(A)) = length(ax) == 1 ? only(ax) : OneTo(prod(length, ax; init=1))
×
2929

2930
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
×
2931
    xit = Iterators.peel(A)
×
2932
    nothing === xit && return _empty_stack(dims, T, S, A)
×
2933
    x1, xrest = xit
×
2934
    ax1 = _iterator_axes(x1)
×
2935
    N1 = length(ax1)+1
×
2936
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
×
2937

2938
    newaxis = _vec_axis(A)
×
2939
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
×
2940
    B = similar(_ensure_array(x1), T, outax...)
×
2941

2942
    if dims == 1
×
2943
        _dim_stack!(Val(1), B, x1, xrest)
×
2944
    elseif dims == 2
×
2945
        _dim_stack!(Val(2), B, x1, xrest)
×
2946
    else
2947
        _dim_stack!(Val(dims), B, x1, xrest)
×
2948
    end
2949
    B
×
2950
end
2951

2952
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
×
2953
    before = ntuple(d -> Colon(), dims - 1)
×
2954
    after = ntuple(d -> Colon(), ndims(B) - dims)
×
2955

2956
    i = firstindex(B, dims)
×
2957
    copyto!(view(B, before..., i, after...), x1)
×
2958

2959
    for x in xrest
×
2960
        _stack_size_check(x, _iterator_axes(x1))
×
2961
        i += 1
×
2962
        @inbounds copyto!(view(B, before..., i, after...), x)
×
2963
    end
×
2964
end
2965

2966
@inline function _stack_size_check(x, ax1::Tuple)
×
2967
    if _iterator_axes(x) != ax1
×
2968
        uax1 = map(UnitRange, ax1)
×
2969
        uaxN = map(UnitRange, _iterator_axes(x))
×
2970
        throw(DimensionMismatch(
×
2971
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
2972
    end
2973
end
2974

2975
_ensure_array(x::AbstractArray) = x
×
2976
_ensure_array(x) = 1:0  # passed to similar, makes stack's output an Array
×
2977

2978
_empty_stack(_...) = throw(ArgumentError("`stack` on an empty collection is not allowed"))
×
2979

2980

2981
## Reductions and accumulates ##
2982

2983
function isequal(A::AbstractArray, B::AbstractArray)
2984
    if A === B return true end
1,406✔
2985
    if axes(A) != axes(B)
2,694✔
2986
        return false
×
2987
    end
2988
    for (a, b) in zip(A, B)
2,686✔
2989
        if !isequal(a, b)
157,855✔
2990
            return false
238✔
2991
        end
2992
    end
314,133✔
2993
    return true
1,109✔
2994
end
2995

2996
function cmp(A::AbstractVector, B::AbstractVector)
×
2997
    for (a, b) in zip(A, B)
×
2998
        if !isequal(a, b)
×
2999
            return isless(a, b) ? -1 : 1
×
3000
        end
3001
    end
×
3002
    return cmp(length(A), length(B))
×
3003
end
3004

3005
"""
3006
    isless(A::AbstractArray{<:Any,0}, B::AbstractArray{<:Any,0})
3007

3008
Return `true` when the only element of `A` is less than the only element of `B`.
3009
"""
3010
function isless(A::AbstractArray{<:Any,0}, B::AbstractArray{<:Any,0})
×
3011
    isless(only(A), only(B))
×
3012
end
3013

3014
"""
3015
    isless(A::AbstractVector, B::AbstractVector)
3016

3017
Return `true` when `A` is less than `B` in lexicographic order.
3018
"""
3019
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
×
3020

3021
function (==)(A::AbstractArray, B::AbstractArray)
9✔
3022
    if axes(A) != axes(B)
522✔
3023
        return false
×
3024
    end
3025
    anymissing = false
9✔
3026
    for (a, b) in zip(A, B)
519✔
3027
        eq = (a == b)
4,340✔
3028
        if ismissing(eq)
26✔
3029
            anymissing = true
×
3030
        elseif !eq
2,984✔
3031
            return false
×
3032
        end
3033
    end
5,710✔
3034
    return anymissing ? missing : true
261✔
3035
end
3036

3037
# _sub2ind and _ind2sub
3038
# fallbacks
3039
function _sub2ind(A::AbstractArray, I...)
3040
    @inline
×
3041
    _sub2ind(axes(A), I...)
636,414✔
3042
end
3043

3044
function _ind2sub(A::AbstractArray, ind)
×
3045
    @inline
×
3046
    _ind2sub(axes(A), ind)
×
3047
end
3048

3049
# 0-dimensional arrays and indexing with []
3050
_sub2ind(::Tuple{}) = 1
×
3051
_sub2ind(::DimsInteger) = 1
×
3052
_sub2ind(::Indices) = 1
×
3053
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
×
3054

3055
# Generic cases
3056
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
×
3057
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
636,414✔
3058
# In 1d, there's a question of whether we're doing cartesian indexing
3059
# or linear indexing. Support only the former.
3060
_sub2ind(inds::Indices{1}, I::Integer...) =
×
3061
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3062
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
3063
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
3064

3065
_sub2ind_recurse(::Any, L, ind) = ind
×
3066
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
×
3067
    @inline
×
3068
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
×
3069
end
3070
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
3071
    @inline
×
3072
    r1 = inds[1]
×
3073
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
1,272,828✔
3074
end
3075

3076
nextL(L, l::Integer) = L*l
×
3077
nextL(L, r::AbstractUnitRange) = L*length(r)
636,414✔
3078
nextL(L, r::Slice) = L*length(r.indices)
×
3079
offsetin(i, l::Integer) = i-1
×
3080
offsetin(i, r::AbstractUnitRange) = i-first(r)
1,272,828✔
3081

3082
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
3083
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
×
3084
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
×
3085
_ind2sub(inds::Indices{1}, ind::Integer) =
×
3086
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3087
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
×
3088

3089
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3090
function _ind2sub_recurse(indslast::NTuple{1}, ind)
×
3091
    @inline
×
3092
    (_lookup(ind, indslast[1]),)
×
3093
end
3094
function _ind2sub_recurse(inds, ind)
×
3095
    @inline
×
3096
    r1 = inds[1]
×
3097
    indnext, f, l = _div(ind, r1)
×
3098
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
×
3099
end
3100

3101
_lookup(ind, d::Integer) = ind+1
×
3102
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
×
3103
_div(ind, d::Integer) = div(ind, d), 1, d
×
3104
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
×
3105

3106
# Vectorized forms
3107
function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
×
3108
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
×
3109
end
3110
_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3111
    _sub2ind_vecs(inds, I1, I...)
3112
_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3113
    _sub2ind_vecs(inds, I1, I...)
3114
function _sub2ind_vecs(inds, I::AbstractVector...)
×
3115
    I1 = I[1]
×
3116
    Iinds = axes1(I1)
×
3117
    for j = 2:length(I)
×
3118
        axes1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(axes1(I[j])))"))
×
3119
    end
×
3120
    Iout = similar(I1)
×
3121
    _sub2ind!(Iout, inds, Iinds, I)
×
3122
    Iout
×
3123
end
3124

3125
function _sub2ind!(Iout, inds, Iinds, I)
×
3126
    @noinline
×
3127
    for i in Iinds
×
3128
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3129
        Iout[i] = sub2ind_vec(inds, i, I)
×
3130
    end
×
3131
    Iout
×
3132
end
3133

3134
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3135
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3136
_sub2ind_vec(i) = ()
×
3137

3138
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3139
    M = length(ind)
×
3140
    t = ntuple(n->similar(ind),Val(N))
×
3141
    for (i,idx) in pairs(IndexLinear(), ind)
×
3142
        sub = _ind2sub(inds, idx)
×
3143
        for j = 1:N
×
3144
            t[j][i] = sub[j]
×
3145
        end
×
3146
    end
×
3147
    t
×
3148
end
3149

3150
## iteration utilities ##
3151

3152
"""
3153
    foreach(f, c...) -> nothing
3154

3155
Call function `f` on each element of iterable `c`.
3156
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3157
any iterator is finished.
3158

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

3162
# Examples
3163
```jldoctest
3164
julia> tri = 1:3:7; res = Int[];
3165

3166
julia> foreach(x -> push!(res, x^2), tri)
3167

3168
julia> res
3169
3-element Vector{$(Int)}:
3170
  1
3171
 16
3172
 49
3173

3174
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3175
1 with a
3176
4 with b
3177
7 with c
3178
```
3179
"""
3180
foreach(f, itr) = (for x in itr; f(x); end; nothing)
48,843✔
3181
foreach(f, itr, itrs...) = (for z in zip(itr, itrs...); f(z...); end; nothing)
×
3182

3183
## map over arrays ##
3184

3185
## transform any set of dimensions
3186
## dims specifies which dimensions will be transformed. for example
3187
## dims==1:2 will call f on all slices A[:,:,...]
3188
"""
3189
    mapslices(f, A; dims)
3190

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

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

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

3200
# Examples
3201
```jldoctest
3202
julia> A = reshape(1:30,(2,5,3))
3203
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3204
[:, :, 1] =
3205
 1  3  5  7   9
3206
 2  4  6  8  10
3207

3208
[:, :, 2] =
3209
 11  13  15  17  19
3210
 12  14  16  18  20
3211

3212
[:, :, 3] =
3213
 21  23  25  27  29
3214
 22  24  26  28  30
3215

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

3218
julia> B = mapslices(f, A, dims=(1,2))
3219
1×4×3 Array{$Int, 3}:
3220
[:, :, 1] =
3221
 1  1  1  1
3222

3223
[:, :, 2] =
3224
 11  11  11  11
3225

3226
[:, :, 3] =
3227
 21  21  21  21
3228

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

3231
julia> B == stack(f2, eachslice(A, dims=3))
3232
true
3233

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

3236
julia> mapslices(g, A, dims=[1,3])
3237
1×5×1 Array{Rational{$Int}, 3}:
3238
[:, :, 1] =
3239
 1//21  3//23  1//5  7//27  9//29
3240

3241
julia> map(g, eachslice(A, dims=2))
3242
5-element Vector{Rational{$Int}}:
3243
 1//21
3244
 3//23
3245
 1//5
3246
 7//27
3247
 9//29
3248

3249
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3250
true
3251
```
3252

3253
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3254
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3255
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3256
values in the slice without affecting `A`.
3257
"""
3258
@constprop :aggressive function mapslices(f, A::AbstractArray; dims)
×
3259
    isempty(dims) && return map(f, A)
×
3260

3261
    for d in dims
×
3262
        d isa Integer || throw(ArgumentError("mapslices: dimension must be an integer, got $d"))
×
3263
        d >= 1 || throw(ArgumentError("mapslices: dimension must be ≥ 1, got $d"))
×
3264
        # Indexing a matrix M[:,1,:] produces a 1-column matrix, but dims=(1,3) here
3265
        # would otherwise ignore 3, and slice M[:,i]. Previously this gave error:
3266
        # BoundsError: attempt to access 2-element Vector{Any} at index [3]
3267
        d > ndims(A) && throw(ArgumentError("mapslices does not accept dimensions > ndims(A) = $(ndims(A)), got $d"))
×
3268
    end
×
3269
    dim_mask = ntuple(d -> d in dims, ndims(A))
×
3270

3271
    # Apply the function to the first slice in order to determine the next steps
3272
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
×
3273
    Aslice = A[idx1...]
×
3274
    r1 = f(Aslice)
×
3275

3276
    res1 = if r1 isa AbstractArray && ndims(r1) > 0
×
3277
        n = sum(dim_mask)
×
3278
        if ndims(r1) > n && any(ntuple(d -> size(r1,d+n)>1, ndims(r1)-n))
×
3279
            s = size(r1)[1:n]
×
3280
            throw(DimensionMismatch("mapslices cannot assign slice f(x) of size $(size(r1)) into output of size $s"))
×
3281
        end
3282
        r1
×
3283
    else
3284
        # If the result of f on a single slice is a scalar then we add singleton
3285
        # dimensions. When adding the dimensions, we have to respect the
3286
        # index type of the input array (e.g. in the case of OffsetArrays)
3287
        _res1 = similar(Aslice, typeof(r1), reduced_indices(Aslice, 1:ndims(Aslice)))
×
3288
        _res1[begin] = r1
×
3289
        _res1
×
3290
    end
3291

3292
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3293
    din = Ref(0)
×
3294
    Rsize = ntuple(ndims(A)) do d
×
3295
        if d in dims
×
3296
            axes(res1, din[] += 1)
×
3297
        else
3298
            axes(A,d)
×
3299
        end
3300
    end
3301
    R = similar(res1, Rsize)
×
3302

3303
    # Determine iteration space. It will be convenient in the loop to mask N-dimensional
3304
    # CartesianIndices, with some trivial dimensions:
3305
    itershape = ntuple(d -> d in dims ? Base.OneTo(1) : axes(A,d), ndims(A))
×
3306
    indices = Iterators.drop(CartesianIndices(itershape), 1)
×
3307

3308
    # That skips the first element, which we already have:
3309
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
×
3310
    concatenate_setindex!(R, res1, ridx...)
×
3311

3312
    # In some cases, we can re-use the first slice for a dramatic performance
3313
    # increase. The slice itself must be mutable and the result cannot contain
3314
    # any mutable containers. The following errs on the side of being overly
3315
    # strict (#18570 & #21123).
3316
    safe_for_reuse = isa(Aslice, StridedArray) &&
×
3317
                     (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number))
3318

3319
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
×
3320
    return R
×
3321
end
3322

3323
@noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
×
3324
    must_extend = any(dim_mask .& size(R) .> 1)
×
3325
    if safe_for_reuse
×
3326
        # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3327
        # so we can reuse Aslice
3328
        for I in indices
×
3329
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
×
3330
            _unsafe_getindex!(Aslice, A, idx...)
×
3331
            r = f(Aslice)
×
3332
            if r isa AbstractArray || must_extend
×
3333
                ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
×
3334
                R[ridx...] = r
×
3335
            else
3336
                ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
×
3337
                R[ridx...] = r
×
3338
            end
3339
        end
×
3340
    else
3341
        # we can't guarantee safety (#18524), so allocate new storage for each slice
3342
        for I in indices
×
3343
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
×
3344
            ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
×
3345
            concatenate_setindex!(R, f(A[idx...]), ridx...)
×
3346
        end
×
3347
    end
3348
end
3349

3350
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
×
3351
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
×
3352

3353
## 1 argument
3354

3355
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
4✔
3356
    for (i,j) in zip(eachindex(dest),eachindex(A))
86,559✔
3357
        val = f(@inbounds A[j])
79,676✔
3358
        @inbounds dest[i] = val
57,386✔
3359
    end
73,898✔
3360
    return dest
45,685✔
3361
end
3362

3363
# map on collections
3364
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
212✔
3365

3366
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
4✔
3367
mapany(f, itr) = Any[f(x) for x in itr]
×
3368

3369
"""
3370
    map(f, c...) -> collection
3371

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

3375
The element type of the result is determined in the same manner as in [`collect`](@ref).
3376

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

3379
# Examples
3380
```jldoctest
3381
julia> map(x -> x * 2, [1, 2, 3])
3382
3-element Vector{Int64}:
3383
 2
3384
 4
3385
 6
3386

3387
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3388
3-element Vector{Int64}:
3389
 11
3390
 22
3391
 33
3392
```
3393
"""
3394
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
2✔
3395

3396
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
×
3397
map(f, ::AbstractSet) = error("map is not defined on sets")
×
3398

3399
## 2 argument
3400
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
×
3401
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
×
3402
        @inbounds a, b = A[j], B[k]
×
3403
        val = f(a, b)
×
3404
        @inbounds dest[i] = val
×
3405
    end
×
3406
    return dest
×
3407
end
3408

3409
## N argument
3410

3411
@inline ith_all(i, ::Tuple{}) = ()
×
3412
function ith_all(i, as)
×
3413
    @_propagate_inbounds_meta
×
3414
    return (as[1][i], ith_all(i, tail(as))...)
×
3415
end
3416

3417
function map_n!(f::F, dest::AbstractArray, As) where F
×
3418
    idxs1 = LinearIndices(As[1])
×
3419
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
×
3420
    for i = idxs1
×
3421
        @inbounds I = ith_all(i, As)
×
3422
        val = f(I...)
×
3423
        @inbounds dest[i] = val
×
3424
    end
×
3425
    return dest
×
3426
end
3427

3428
"""
3429
    map!(function, destination, collection...)
3430

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

3434
$(_DOCS_ALIASING_WARNING)
3435

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

3438
# Examples
3439
```jldoctest
3440
julia> a = zeros(3);
3441

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

3444
julia> a
3445
3-element Vector{Float64}:
3446
 2.0
3447
 4.0
3448
 6.0
3449

3450
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3451
5-element Vector{$(Int)}:
3452
 101
3453
 103
3454
 105
3455
   0
3456
   0
3457
```
3458
"""
3459
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
×
3460
    @assert !isempty(As) # should dispatch to map!(f, A)
×
3461
    map_n!(f, dest, As)
×
3462
end
3463

3464
"""
3465
    map!(function, array)
3466

3467
Like [`map`](@ref), but stores the result in the same array.
3468
!!! compat "Julia 1.12"
3469
    This method requires Julia 1.12 or later. To support previous versions too,
3470
    use the equivalent `map!(function, array, array)`.
3471

3472
# Examples
3473
```jldoctest
3474
julia> a = [1 2 3; 4 5 6];
3475

3476
julia> map!(x -> x^3, a);
3477

3478
julia> a
3479
2×3 Matrix{$Int}:
3480
  1    8   27
3481
 64  125  216
3482
```
3483
"""
3484
map!(f::F, inout::AbstractArray) where F = map!(f, inout, inout)
×
3485

3486
"""
3487
    map(f, A::AbstractArray...) -> N-array
3488

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

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

3494
# Examples
3495
```
3496
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3497
2×2 Matrix{Rational{$Int}}:
3498
 1//4  2//3
3499
 3//2  4//1
3500

3501
julia> map(+, [1 2; 3 4], zeros(2,1))
3502
ERROR: DimensionMismatch
3503

3504
julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1))  # iterates until 3rd is exhausted
3505
3-element Vector{Float64}:
3506
   2.0
3507
  13.0
3508
 102.0
3509
```
3510
"""
3511
map(f, it, iters...) = collect(Generator(f, it, iters...))
×
3512

3513
# Generic versions of push! for AbstractVector
3514
# These are specialized further for Vector for faster resizing and setindexing
3515
function push!(a::AbstractVector{T}, item) where T
×
3516
    # convert first so we don't grow the array if the assignment won't work
3517
    itemT = item isa T ? item : convert(T, item)::T
×
3518
    new_length = length(a) + 1
×
3519
    resize!(a, new_length)
×
3520
    a[end] = itemT
×
3521
    return a
×
3522
end
3523

3524
# specialize and optimize the single argument case
3525
function push!(a::AbstractVector{Any}, @nospecialize x)
×
3526
    new_length = length(a) + 1
×
3527
    resize!(a, new_length)
×
3528
    a[end] = x
×
3529
    return a
×
3530
end
3531
function push!(a::AbstractVector{Any}, @nospecialize x...)
×
3532
    @_terminates_locally_meta
×
3533
    na = length(a)
×
3534
    nx = length(x)
×
3535
    resize!(a, na + nx)
×
3536
    e = lastindex(a) - nx
×
3537
    for i = 1:nx
×
3538
        a[e+i] = x[i]
×
3539
    end
×
3540
    return a
×
3541
end
3542

3543
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3544
# (note: must not cause a dispatch loop when 1-item case is not defined)
3545
push!(A, a, b) = push!(push!(A, a), b)
×
3546
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
×
3547
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3548
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
×
3549

3550
# sizehint! does not nothing by default
3551
sizehint!(a::AbstractVector, _) = a
×
3552

3553
## hashing AbstractArray ##
3554

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

3563
    # For short arrays, it's not worth doing anything complicated
3564
    if length(A) < 8192
1,880✔
3565
        for x in A
3,748✔
3566
            h = hash(x, h)
266,215✔
3567
        end
530,552✔
3568
        return h
1,880✔
3569
    end
3570

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

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

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

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

3604
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3605
        linidx = key_to_linear[keyidx]
×
3606
        linidx < fibskip + first_linear && break
×
3607
        linidx -= fibskip
×
3608
        keyidx = linear_to_key[linidx]
×
3609

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

3620
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3621
        keyidx = findprev(!isequal(elt), A, keyidx)
×
3622
        keyidx === nothing && break
×
3623
    end
×
3624

3625
    return h
×
3626
end
3627

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

3636

3637
## keepat! ##
3638

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

3641
function _keepat!(a::AbstractVector, inds)
×
3642
    local prev
×
3643
    i = firstindex(a)
×
3644
    for k in inds
×
3645
        if @isdefined(prev)
×
3646
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
×
3647
        end
3648
        ak = a[k] # must happen even when i==k for bounds checking
×
3649
        if i != k
×
3650
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
×
3651
        end
3652
        prev = k
×
3653
        i = nextind(a, i)
×
3654
    end
×
3655
    deleteat!(a, i:lastindex(a))
×
3656
    return a
×
3657
end
3658

3659
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
×
3660
    length(m) == length(a) || throw(BoundsError(a, m))
×
3661
    j = firstindex(a)
×
3662
    for i in eachindex(a, m)
×
3663
        @inbounds begin
×
3664
            if m[i]
×
3665
                i == j || (a[j] = a[i])
×
3666
                j = nextind(a, j)
×
3667
            end
3668
        end
3669
    end
×
3670
    deleteat!(a, j:lastindex(a))
×
3671
end
3672

3673
"""
3674
    circshift!(a::AbstractVector, shift::Integer)
3675

3676
Circularly shift, or rotate, the data in vector `a` by `shift` positions.
3677

3678
# Examples
3679

3680
```jldoctest
3681
julia> circshift!([1, 2, 3, 4, 5], 2)
3682
5-element Vector{Int64}:
3683
 4
3684
 5
3685
 1
3686
 2
3687
 3
3688

3689
julia> circshift!([1, 2, 3, 4, 5], -2)
3690
5-element Vector{Int64}:
3691
 3
3692
 4
3693
 5
3694
 1
3695
 2
3696
```
3697
"""
3698
function circshift!(a::AbstractVector, shift::Integer)
×
3699
    n = length(a)
×
3700
    n == 0 && return a
×
3701
    shift = mod(shift, n)
×
3702
    shift == 0 && return a
×
3703
    l = lastindex(a)
×
3704
    reverse!(a, firstindex(a), l-shift)
×
3705
    reverse!(a, l-shift+1, lastindex(a))
×
3706
    reverse!(a)
×
3707
    return a
×
3708
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc