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

JuliaLang / julia / #38044

13 Apr 2025 03:17PM UTC coverage: 22.84% (+2.9%) from 19.945%
#38044

push

local

web-flow
Forward `to_shape` for `AbstractOneTo` to `Integer` method (#57990)

This allows custom `Integer` types to add methods to `to_shape` and have
the behavior of `OneTo` be altered accordingly.

2 of 3 new or added lines in 1 file covered. (66.67%)

61 existing lines in 7 files now uncovered.

11320 of 49563 relevant lines covered (22.84%)

110749.05 hits per line

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

17.34
/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,541✔
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,236✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
65,056✔
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)
4,961✔
97
    @inline
43,403✔
98
    map(unchecked_oneto, size(A))
9,243,829✔
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])
5,947,156✔
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)
99,126✔
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
407✔
216
nextind(::AbstractArray, i::Integer) = Int(i)+1
137,026✔
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)))
884,346✔
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))
639,795✔
322

323

324
# we unroll the join for easier inference
325
_join_comma_and(indsA, indsB) = LazyString(indsA, " and ", indsB)
×
326
_join_comma_and(indsA, indsB, indsC...) = LazyString(indsA, ", ", _join_comma_and(indsB, indsC...))
×
327
@noinline function throw_eachindex_mismatch_indices(indices_str, indsA, indsBs...)
×
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))
5,294,330✔
392
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
×
393
    @inline
×
394
    indsA = eachindex(IndexLinear(), A)
×
395
    indsBs = map(X -> eachindex(IndexLinear(), X), B)
×
396
    all(==(indsA), indsBs) ||
×
397
        throw_eachindex_mismatch_indices("indices", indsA, indsBs...)
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)))
2,381,130✔
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,218✔
448
firstindex(a, d) = (@inline; first(axes(a, d)))
×
449

450
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
188✔
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]
121,666✔
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,886✔
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)
2,480✔
686
    @inline
417,306✔
687
    return checkindex(Bool, eachindex(IndexLinear(), A), i)
4,389,696✔
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...)
2,480✔
696
    @inline
417,306✔
697
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
2,054,078✔
698
    nothing
417,306✔
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 &
247,162✔
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))
34✔
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,489,963✔
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,973,265✔
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,625,759✔
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,487✔
765
        b &= checkindex(Bool, inds, i)
27,924✔
766
    end
27,924✔
767
    b
2,487✔
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)
5✔
819
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, axes(a))
5✔
820
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, dims)
546,878✔
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)
14,712✔
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))
547,098✔
832
# similar creates an Array by default
833
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N}    = Array{T,N}(undef, dims)
14,712✔
834

835
to_shape(::Tuple{}) = ()
×
836
to_shape(dims::Dims) = dims
×
837
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
6,825✔
838
# each dimension
839
to_shape(i::Int) = i
×
840
to_shape(i::Integer) = Int(i)
216✔
841
to_shape(r::AbstractOneTo) = _to_shape(last(r))
6,824✔
842
_to_shape(x::Integer) = to_shape(x)
216✔
NEW
843
_to_shape(x) = Int(x)
×
UNCOV
844
to_shape(r::AbstractUnitRange) = r
×
845

846
"""
847
    similar(storagetype, axes)
848

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

853
**Examples**:
854

855
    similar(Array{Int}, axes(A))
856

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

863
    similar(BitArray, (axes(A, 2),))
864

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

874
"""
875
    empty(v::AbstractVector, [eltype])
876

877
Create an empty vector similar to `v`, optionally changing the `eltype`.
878

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

881
# Examples
882

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

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

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

897
"""
898
    copy!(dst, src) -> dst
899

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

907
$(_DOCS_ALIASING_WARNING)
908

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

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

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

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

934
## from general iterable to any array
935

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

940
function copyto!(dest::AbstractArray, src)
14,172✔
941
    destiter = eachindex(dest)
14,172✔
942
    y = iterate(destiter)
14,172✔
943
    for x in src
28,482✔
944
        y === nothing &&
69,323✔
945
            throw(ArgumentError("destination has fewer elements than required"))
946
        dest[y[1]] = x
69,323✔
947
        y = iterate(destiter, y[2])
125,188✔
948
    end
125,622✔
949
    return dest
14,172✔
950
end
951

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

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

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

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

1038
"""
1039
    copyto!(dest::AbstractArray, src) -> dest
1040

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

1045
See also [`copy!`](@ref Base.copy!), [`copy`](@ref).
1046

1047
$(_DOCS_ALIASING_WARNING)
1048

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

1053
julia> y = zeros(7);
1054

1055
julia> copyto!(y, x);
1056

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

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

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

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

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

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

1147
function copy(a::AbstractArray)
×
1148
    @_propagate_inbounds_meta
×
1149
    copymutable(a)
6,360✔
1150
end
1151

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

1177
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
3✔
1178

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

1184
"""
1185
    copymutable(a)
1186

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

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

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

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

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

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

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

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

1243
isempty(a::AbstractArray) = (length(a) == 0)
4,297,891✔
1244

1245

1246
## range conversions ##
1247

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

1255
## unsafe/pointer conversions ##
1256

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

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

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

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

1289
Return a subset of array `A` as selected by the indices `inds`.
1290

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

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

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

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

1308
julia> getindex(A, 1)
1309
1
1310

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

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

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

1325
julia> getindex(A, CartesianIndex(2, 1))
1326
3
1327

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

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

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

1352
@inline unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
×
1353

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

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

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

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

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

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

1422
"""
1423
    setindex!(A, X, inds...)
1424
    A[inds...] = X
1425

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

1429
$(_DOCS_ALIASING_WARNING)
1430

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

1435
julia> setindex!(A, [10, 20], [1, 2]);
1436

1437
julia> A[[3, 4]] = [30, 40];
1438

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

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

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

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

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

1487
_unsetindex!(A::AbstractArray, i::Integer) = _unsetindex!(A, to_index(i))
×
1488

1489
"""
1490
    parent(A)
1491

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

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

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

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

1517
parent(a::AbstractArray) = a
×
1518

1519
## rudimentary aliasing detection ##
1520
"""
1521
    Base.unalias(dest, A)
1522

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

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

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

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

1539
"""
1540
    Base.unaliascopy(A)
1541

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

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

1564
"""
1565
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1566

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

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

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

1585
"""
1586
    Base.dataids(A::AbstractArray)
1587

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

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

1601
## get (getindex with a default value) ##
1602

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

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

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

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

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

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

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

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

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

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

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

1668
typed_vcat(::Type{T}) where {T} = Vector{T}()
×
1669
typed_hcat(::Type{T}) where {T} = Vector{T}()
×
1670

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

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

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

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

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

1694
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
1695
    pos = 1
2✔
1696
    for k=1:Int(length(V))::Int
3✔
1697
        Vk = V[k]
82✔
1698
        p1 = pos + Int(length(Vk))::Int - 1
82✔
1699
        a[pos:p1] = Vk
102✔
1700
        pos = p1+1
82✔
1701
    end
84✔
1702
    a
2✔
1703
end
1704

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

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

1714

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

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

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

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

1775
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
4✔
1776

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

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

1783
## cat: general case
1784

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

1791
cat_length(::Any) = 1
×
1792
cat_length(a::AbstractArray) = length(a)
×
1793

1794
cat_ndims(a) = 0
×
1795
cat_ndims(a::AbstractArray) = ndims(a)
×
1796

1797
cat_indices(A, d) = OneTo(1)
1✔
1798
cat_indices(A::AbstractArray, d) = axes(A, d)
3✔
1799

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

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

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

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

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

1855
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
3✔
1856

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

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

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

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

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

1894
"""
1895
    vcat(A...)
1896

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

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

1903
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1904

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

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

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

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

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

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

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

1938
julia> vs = [[1, 2], [3, 4], [5, 6]];
1939

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

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

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

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

1964
See also [`vcat`](@ref), [`hvcat`](@ref).
1965

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

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

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

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

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

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

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

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

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

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

2008
"""
2009
    cat(A...; dims)
2010

2011
Concatenate the input arrays along the dimensions specified in `dims`.
2012

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

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

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

2027
The keyword also accepts `Val(dims)`.
2028

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

2032
# Examples
2033

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

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

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

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

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

2059
# Extended Help
2060

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

2065
julia> b = ones(2, 2, 4);
2066

2067
julia> c = cat(a, b; dims=3);
2068

2069
julia> size(c) == (2, 2, 7)
2070
true
2071
```
2072

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

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

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

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

2101
```jldoctest
2102
julia> a = "aaa";
2103

2104
julia> b = "bbb";
2105

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

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

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

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

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

2141
# 2d horizontal and vertical concatenation
2142

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2258
## N-dimensional concatenation ##
2259

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

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

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

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

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

2288
[:, :, 2] =
2289
 4  5  6
2290

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

2297
[:, :, 2] =
2298
 3
2299
 4
2300

2301
[:, :, 3] =
2302
 5
2303
 6
2304

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

2310
[:, :, 2] =
2311
 3  4
2312

2313
[:, :, 3] =
2314
 5  6
2315

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

2321
[:, :, 2] =
2322
 4  5  6
2323
```
2324

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

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

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

2355

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

2359
# 1-dimensional hvncat methods
2360

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

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

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

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

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

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

2402
    nd = N
×
2403

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

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

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

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

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

2456
# 0-dimensional cases for balanced and unbalanced hvncat method
2457

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

2461

2462
# balanced dimensions hvncat methods
2463

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

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

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

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

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

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

2534
    d1 = row_first ? 2 : 1
×
2535
    d2 = row_first ? 1 : 2
×
2536

2537
    outdims = zeros(Int, N)
×
2538

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

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

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

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

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

2611

2612
# unbalanced dimensions hvncat methods
2613

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

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

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

2632
    d1 = row_first ? 2 : 1
×
2633
    d2 = row_first ? 1 : 2
×
2634

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

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

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

2666
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
×
2667

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

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

2690
    if row_first
×
2691
        outdims[1], outdims[2] = outdims[2], outdims[1]
×
2692
    end
2693

2694
    # @assert all(==(0), currentdims)
2695
    # @assert all(==(0), blockcounts)
2696

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

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

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

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

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

2753
"""
2754
    stack(iter; [dims])
2755

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

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

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

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

2772
!!! compat "Julia 1.9"
2773
    This function requires at least Julia 1.9.
2774

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

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

2784
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2785
true
2786

2787
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2788
true
2789

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

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

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

2804
julia> x = rand(3,4);
2805

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

2810
Higher-dimensional examples:
2811

2812
```jldoctest
2813
julia> A = rand(5, 7, 11);
2814

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

2817
julia> (element = size(first(E)), container = size(E))
2818
(element = (5, 11), container = (7,))
2819

2820
julia> stack(E) |> size
2821
(5, 11, 7)
2822

2823
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2824
true
2825

2826
julia> A == stack(E; dims=2)
2827
true
2828

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

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

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

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

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

2846
"""
2847
    stack(f, args...; [dims])
2848

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

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

2856
See also [`mapslices`](@ref), [`eachcol`](@ref).
2857

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

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

2876
_stack(dims::Union{Integer, Colon}, iter) = _stack(dims, IteratorSize(iter), iter)
×
2877

2878
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
×
2879

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

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

2911
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
×
2912
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
×
2913
_iterator_axes(x, ::IteratorSize) = axes(x)
×
2914

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

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

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

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

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

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

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

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

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

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

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

2982

2983
## Reductions and accumulates ##
2984

2985
function isequal(A::AbstractArray, B::AbstractArray)
2986
    if A === B return true end
1,402✔
2987
    if axes(A) != axes(B)
2,684✔
2988
        return false
×
2989
    end
2990
    for (a, b) in zip(A, B)
2,676✔
2991
        if !isequal(a, b)
157,865✔
2992
            return false
235✔
2993
        end
2994
    end
314,161✔
2995
    return true
1,107✔
2996
end
2997

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

3007
"""
3008
    isless(A::AbstractArray{<:Any,0}, B::AbstractArray{<:Any,0})
3009

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

3016
"""
3017
    isless(A::AbstractVector, B::AbstractVector)
3018

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

3023
function (==)(A::AbstractArray, B::AbstractArray)
9✔
3024
    if axes(A) != axes(B)
1,266✔
3025
        return false
×
3026
    end
3027
    anymissing = false
9✔
3028
    for (a, b) in zip(A, B)
1,263✔
3029
        eq = (a == b)
9,353✔
3030
        if ismissing(eq)
26✔
3031
            anymissing = true
×
3032
        elseif !eq
6,286✔
3033
            return false
×
3034
        end
3035
    end
11,942✔
3036
    return anymissing ? missing : true
633✔
3037
end
3038

3039
# _sub2ind and _ind2sub
3040
# fallbacks
3041
function _sub2ind(A::AbstractArray, I...)
3042
    @inline
×
3043
    _sub2ind(axes(A), I...)
619,432✔
3044
end
3045

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

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

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

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

3078
nextL(L, l::Integer) = L*l
×
3079
nextL(L, r::AbstractUnitRange) = L*length(r)
619,432✔
3080
nextL(L, r::Slice) = L*length(r.indices)
×
3081
offsetin(i, l::Integer) = i-1
×
3082
offsetin(i, r::AbstractUnitRange) = i-first(r)
1,238,864✔
3083

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

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

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

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

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

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

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

3152
## iteration utilities ##
3153

3154
"""
3155
    foreach(f, c...) -> nothing
3156

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

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

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

3168
julia> foreach(x -> push!(res, x^2), tri)
3169

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

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

3185
## map over arrays ##
3186

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

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

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

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

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

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

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

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

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

3225
[:, :, 2] =
3226
 11  11  11  11
3227

3228
[:, :, 3] =
3229
 21  21  21  21
3230

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

3233
julia> B == stack(f2, eachslice(A, dims=3))
3234
true
3235

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3355
## 1 argument
3356

3357
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
4✔
3358
    for (i,j) in zip(eachindex(dest),eachindex(A))
227,604✔
3359
        val = f(@inbounds A[j])
207,810✔
3360
        @inbounds dest[i] = val
149,361✔
3361
    end
191,345✔
3362
    return dest
120,227✔
3363
end
3364

3365
# map on collections
3366
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
226✔
3367

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

3371
"""
3372
    map(f, c...) -> collection
3373

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

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

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

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

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

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

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

3411
## N argument
3412

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

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

3430
"""
3431
    map!(function, destination, collection...)
3432

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

3436
$(_DOCS_ALIASING_WARNING)
3437

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

3440
# Examples
3441
```jldoctest
3442
julia> a = zeros(3);
3443

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

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

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

3466
"""
3467
    map!(function, array)
3468

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

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

3478
julia> map!(x -> x^3, a);
3479

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

3488
"""
3489
    map(f, A::AbstractArray...) -> N-array
3490

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

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

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

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

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

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

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

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

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

3555
## hashing AbstractArray ##
3556

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

3565
    # For short arrays, it's not worth doing anything complicated
3566
    if length(A) < 8192
1,882✔
3567
        for x in A
3,752✔
3568
            h = hash(x, h)
266,364✔
3569
        end
530,848✔
3570
        return h
1,882✔
3571
    end
3572

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

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

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

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

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

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

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

3627
    return h
×
3628
end
3629

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

3638

3639
## keepat! ##
3640

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

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

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

3675
"""
3676
    circshift!(a::AbstractVector, shift::Integer)
3677

3678
Circularly shift, or rotate, the data in vector `a` by `shift` positions.
3679

3680
# Examples
3681

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

3691
julia> circshift!([1, 2, 3, 4, 5], -2)
3692
5-element Vector{Int64}:
3693
 3
3694
 4
3695
 5
3696
 1
3697
 2
3698
```
3699
"""
3700
function circshift!(a::AbstractVector, shift::Integer)
×
3701
    n = length(a)
×
3702
    n == 0 && return a
×
3703
    shift = mod(shift, n)
×
3704
    shift == 0 && return a
×
3705
    l = lastindex(a)
×
3706
    reverse!(a, firstindex(a), l-shift)
×
3707
    reverse!(a, l-shift+1, lastindex(a))
×
3708
    reverse!(a)
×
3709
    return a
×
3710
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