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

JuliaLang / julia / 1443

14 Feb 2026 04:10PM UTC coverage: 76.702% (-0.02%) from 76.723%
1443

push

buildkite

web-flow
Updating mmtk-julia binding version and checksums (#60991)

63000 of 82136 relevant lines covered (76.7%)

23247294.77 hits per line

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

90.58
/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
134,125✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
14,398✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
21,042✔
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
function size(t::AbstractArray, dim)
78,622✔
43
    d = Int(dim)::Int
199,955,871✔
44
    s = size(t)
200,873,445✔
45
    d <= length(s) ? s[d] : 1
200,863,221✔
46
end
47

48
"""
49
    axes(A, d)
50

51
Return the valid range of indices for array `A` along dimension `d`.
52

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

55
# Examples
56

57
```jldoctest
58
julia> A = fill(1, (5,6,7));
59

60
julia> axes(A, 2)
61
Base.OneTo(6)
62

63
julia> axes(A, 4) == 1:1  # all dimensions d > ndims(A) have size 1
64
true
65
```
66

67
# Usage note
68

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

73
```julia
74
ix = axes(v, 1)
75
ix[2:end]          # will work for eg Vector, but may fail in general
76
ix[(begin+1):end]  # works for generalized indexes
77
```
78
"""
79
function axes(A::AbstractArray{T,N}, d) where {T,N}
964✔
80
    @inline
24,151,307✔
81
    d::Integer <= N ? axes(A)[d] : OneTo(1)
24,286,743✔
82
end
83

84
"""
85
    axes(A)
86

87
Return the tuple of valid indices for array `A`.
88

89
See also [`size`](@ref), [`keys`](@ref), [`eachindex`](@ref).
90

91
# Examples
92

93
```jldoctest
94
julia> A = fill(1, (5,6,7));
95

96
julia> axes(A)
97
(Base.OneTo(5), Base.OneTo(6), Base.OneTo(7))
98
```
99
"""
100
function axes(A)
10,039✔
101
    @inline
2,480,782,274✔
102
    map(unchecked_oneto, size(A))
5,862,860,353✔
103
end
104

105
"""
106
    has_offset_axes(A)
107
    has_offset_axes(A, B, ...)
108

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

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

124

125
"""
126
    require_one_based_indexing(A::AbstractArray)
127
    require_one_based_indexing(A,B...)
128

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

132
!!! compat "Julia 1.2"
133
     This function requires at least Julia 1.2.
134
"""
135
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"))
439,456,068✔
136

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

144
"""
145
    keys(a::AbstractArray)
146

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

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

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

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

165
julia> keys([4 5; 6 7])
166
CartesianIndices((2, 2))
167
```
168
"""
169
keys(a::AbstractArray) = CartesianIndices(axes(a))
2,647✔
170
keys(a::AbstractVector) = LinearIndices(a)
5,187,354✔
171

172
"""
173
    keytype(T::Type{<:AbstractArray})
174
    keytype(A::AbstractArray)
175

176
Return the key type of an array. This is equal to the
177
[`eltype`](@ref) of the result of `keys(...)`, and is provided
178
mainly for compatibility with the dictionary interface.
179

180
# Examples
181
```jldoctest
182
julia> keytype([1, 2, 3]) == Int
183
true
184

185
julia> keytype([1 2; 3 4])
186
CartesianIndex{2}
187
```
188

189
!!! compat "Julia 1.2"
190
     For arrays, this function requires at least Julia 1.2.
191
"""
192
keytype(a::AbstractArray) = keytype(typeof(a))
90,118,401✔
193
keytype(::Type{Union{}}, slurp...) = eltype(Union{})
×
194

195
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
6✔
196
keytype(A::Type{<:AbstractVector}) = Int
90,118,398✔
197

198
valtype(a::AbstractArray) = valtype(typeof(a))
45✔
199
valtype(::Type{Union{}}, slurp...) = eltype(Union{})
×
200

201
"""
202
    valtype(T::Type{<:AbstractArray})
203
    valtype(A::AbstractArray)
204

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

208
# Examples
209
```jldoctest
210
julia> valtype(["one", "two", "three"])
211
String
212
```
213

214
!!! compat "Julia 1.2"
215
     For arrays, this function requires at least Julia 1.2.
216
"""
217
valtype(A::Type{<:AbstractArray}) = eltype(A)
51✔
218

219
prevind(::AbstractArray, i::Integer) = Int(i)-1
426,939✔
220
nextind(::AbstractArray, i::Integer) = Int(i)+1
105,039,553✔
221

222

223
"""
224
    eltype(type)
225

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

232
See also [`keytype`](@ref), [`typeof`](@ref).
233

234
# Examples
235
```jldoctest
236
julia> eltype(fill(1f0, (2,2)))
237
Float32
238

239
julia> eltype(fill(0x1, (2,2)))
240
UInt8
241
```
242
"""
243
eltype(::Type) = Any
44,004✔
244
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
×
245
eltype(x) = eltype(typeof(x))
204,246,408✔
246
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
306,540,866✔
247

248
"""
249
    elsize(type)
250

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

255
# Examples
256
```jldoctest
257
julia> Base.elsize(rand(Float32, 10))
258
4
259
```
260
"""
261
elsize(A::AbstractArray) = elsize(typeof(A))
254,500,667✔
262

263
"""
264
    ndims(A::AbstractArray)::Integer
265

266
Return the number of dimensions of `A`.
267

268
See also [`size`](@ref), [`axes`](@ref).
269

270
# Examples
271
```jldoctest
272
julia> A = fill(1, (3,4,5));
273

274
julia> ndims(A)
275
3
276
```
277
"""
278
ndims(::AbstractArray{T,N}) where {T,N} = N::Int
193,936,340✔
279
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N::Int
237✔
280
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
×
281

282
"""
283
    length(collection)::Integer
284

285
Return the number of elements in the collection.
286

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

289
See also [`size`](@ref), [`ndims`](@ref), [`eachindex`](@ref).
290

291
# Examples
292
```jldoctest
293
julia> length(1:5)
294
5
295

296
julia> length([1, 2, 3, 4])
297
4
298

299
julia> length([1 2; 3 4])
300
4
301
```
302
"""
303
length
304

305
"""
306
    length(A::AbstractArray)
307

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

310
# Examples
311
```jldoctest
312
julia> length([1, 2, 3, 4])
313
4
314

315
julia> length([1 2; 3 4])
316
4
317
```
318
"""
319
length(t::AbstractArray)
320

321
# `eachindex` is mostly an optimization of `keys`
322
eachindex(itrs...) = keys(itrs...)
12,040,321✔
323

324
# eachindex iterates over all indices. IndexCartesian definitions are later.
325
eachindex(A::AbstractVector) = (@inline(); axes1(A))
40,059,109✔
326

327

328
# we unroll the join for easier inference
329
_join_comma_and(indsA, indsB) = LazyString(indsA, " and ", indsB)
3✔
330
_join_comma_and(indsA, indsB, indsC...) = LazyString(indsA, ", ", _join_comma_and(indsB, indsC...))
×
331
@noinline function throw_eachindex_mismatch_indices(indices_str, indsA, indsBs...)
3✔
332
    throw(DimensionMismatch(
3✔
333
            LazyString("all inputs to eachindex must have the same ", indices_str, ", got ",
334
                _join_comma_and(indsA, indsBs...))))
335
end
336

337
"""
338
    eachindex(A...)
339
    eachindex(::IndexStyle, A::AbstractArray...)
340

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

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

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

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

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

365
# Examples
366
```jldoctest
367
julia> A = [10 20; 30 40];
368

369
julia> for i in eachindex(A) # linear indexing
370
           println("A[", i, "] == ", A[i])
371
       end
372
A[1] == 10
373
A[2] == 30
374
A[3] == 20
375
A[4] == 40
376

377
julia> for i in eachindex(view(A, 1:2, 1:1)) # Cartesian indexing
378
           println(i)
379
       end
380
CartesianIndex(1, 1)
381
CartesianIndex(2, 1)
382
```
383
"""
384
eachindex(A::AbstractArray) = (@inline(); eachindex(IndexStyle(A), A))
992,791✔
385

386
function eachindex(A::AbstractArray, B::AbstractArray)
21✔
387
    @inline
4,093✔
388
    eachindex(IndexStyle(A,B), A, B)
4,093✔
389
end
390
function eachindex(A::AbstractArray, B::AbstractArray...)
6✔
391
    @inline
4,905✔
392
    eachindex(IndexStyle(A,B...), A, B...)
4,905✔
393
end
394
eachindex(::IndexLinear, A::Union{Array, Memory}) = unchecked_oneto(length(A))
1,089,192,708✔
395
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
128,669,752✔
396
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
3,621,865,204✔
397
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
3✔
398
    @inline
10,801✔
399
    indsA = eachindex(IndexLinear(), A)
10,801✔
400
    indsBs = map(X -> eachindex(IndexLinear(), X), B)
26,504✔
401
    all(==(indsA), indsBs) ||
10,804✔
402
        throw_eachindex_mismatch_indices("indices", indsA, indsBs...)
403
    indsA
10,798✔
404
end
405

406
# keys with an IndexStyle
407
keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...)
×
408

409
"""
410
    lastindex(collection)::Integer
411
    lastindex(collection, d)::Integer
412

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

415
The syntaxes `A[end]` and `A[end, end]` lower to `A[lastindex(A)]` and
416
`A[lastindex(A, 1), lastindex(A, 2)]`, respectively.
417

418
See also [`axes`](@ref), [`firstindex`](@ref), [`eachindex`](@ref), [`prevind`](@ref).
419

420
# Examples
421
```jldoctest
422
julia> lastindex([1,2,4])
423
3
424

425
julia> lastindex(rand(3,4,5), 2)
426
4
427
```
428
"""
429
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
404,938,815✔
430
lastindex(a, d) = (@inline; last(axes(a, d)))
1,471,762✔
431

432
"""
433
    firstindex(collection)::Integer
434
    firstindex(collection, d)::Integer
435

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

438
The syntaxes `A[begin]` and `A[1, begin]` lower to `A[firstindex(A)]` and
439
`A[1, firstindex(A, 2)]`, respectively.
440

441
See also [`first`](@ref), [`axes`](@ref), [`lastindex`](@ref), [`nextind`](@ref).
442

443
# Examples
444
```jldoctest
445
julia> firstindex([1,2,4])
446
1
447

448
julia> firstindex(rand(3,4,5), 2)
449
1
450
```
451
"""
452
firstindex(a::AbstractArray) = (@inline; first(eachindex(IndexLinear(), a)))
801,298,142✔
453
firstindex(a, d) = (@inline; first(axes(a, d)))
1,668,860✔
454

455
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
1,313,825✔
456

457
"""
458
    first(coll)
459

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

463
See also [`only`](@ref), [`firstindex`](@ref), [`last`](@ref).
464

465
# Examples
466
```jldoctest
467
julia> first(2:2:10)
468
2
469

470
julia> first([1; 2; 3; 4])
471
1
472
```
473
"""
474
function first(itr)
3,423✔
475
    x = iterate(itr)
13,373✔
476
    x === nothing && throw(ArgumentError("collection must be non-empty"))
10,131✔
477
    x[1]
10,125✔
478
end
479

480
"""
481
    first(itr, n::Integer)
482

483
Get the first `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
484
long enough.
485

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

489
See also [`startswith`](@ref), [`Iterators.take`](@ref).
490

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

498
julia> first(1:6, 10)
499
1:6
500

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

512
"""
513
    last(coll)
514

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

519
See also [`first`](@ref), [`endswith`](@ref).
520

521
# Examples
522
```jldoctest
523
julia> last(1:2:10)
524
9
525

526
julia> last([1; 2; 3; 4])
527
4
528
```
529
"""
530
last(a) = a[end]
2,617,829✔
531

532
"""
533
    last(itr, n::Integer)
534

535
Get the last `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
536
long enough.
537

538
!!! compat "Julia 1.6"
539
    This method requires at least Julia 1.6.
540

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

548
julia> last(1:6, 10)
549
1:6
550

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

562
"""
563
    strides(A)
564

565
Return a tuple of the memory strides in each dimension.
566

567
See also [`stride`](@ref).
568

569
# Examples
570
```jldoctest
571
julia> A = fill(1, (3,4,5));
572

573
julia> strides(A)
574
(1, 3, 12)
575
```
576
"""
577
function strides end
578

579
"""
580
    stride(A, k::Integer)
581

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

584
See also [`strides`](@ref).
585

586
# Examples
587
```jldoctest
588
julia> A = fill(1, (3,4,5));
589

590
julia> stride(A,2)
591
3
592

593
julia> stride(A,3)
594
12
595
```
596
"""
597
function stride(A::AbstractArray, k::Integer)
471✔
598
    st = strides(A)
2,325✔
599
    k ≤ ndims(A) && return st[k]
2,181✔
600
    ndims(A) == 0 && return 1
21✔
601
    sz = size(A)
21✔
602
    s = st[1] * sz[1]
21✔
603
    for i in 2:ndims(A)
21✔
604
        s += st[i] * sz[i]
6✔
605
    end
6✔
606
    return s
21✔
607
end
608

609
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
37,597,578✔
610
size_to_strides(s, d) = (s,)
5,076✔
611
size_to_strides(s) = ()
×
612

613
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
12✔
614
    @boundscheck checkbounds(A, I...)
111✔
615
    return true
93✔
616
end
617

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

639
## Bounds checking ##
640

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

655
"""
656
    checkbounds(Bool, A, I...)
657

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

663
See also [`checkindex`](@ref).
664

665
# Examples
666
```jldoctest
667
julia> A = rand(3, 3);
668

669
julia> checkbounds(Bool, A, 2)
670
true
671

672
julia> checkbounds(Bool, A, 3, 4)
673
false
674

675
julia> checkbounds(Bool, A, 1:3)
676
true
677

678
julia> checkbounds(Bool, A, 1:3, 2:4)
679
false
680
```
681
"""
682
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
11,982✔
683
    @inline
663,346,164✔
684
    checkbounds_indices(Bool, axes(A), I)
877,228,742✔
685
end
686

687
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index;
688
# indices that do not allow linear indexing (e.g., logical arrays, cartesian indices, etc)
689
# must add specialized methods to implement their restrictions
690
function checkbounds(::Type{Bool}, A::AbstractArray, i)
227✔
691
    @inline
2,183,747,611✔
692
    return checkindex(Bool, eachindex(IndexLinear(), A), i)
3,907,768,945✔
693
end
694

695
"""
696
    checkbounds(A, I...)
697

698
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
699
"""
700
checkbounds(A::AbstractArray, I...)
701

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

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

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

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

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

720
See also [`checkbounds`](@ref).
721
"""
722
function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{Any, Vararg})
10,390✔
723
    @inline
58,050,569✔
724
    return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
1,949,097,436✔
725
        checkbounds_indices(Bool, safe_tail(inds), tail(I))
726
end
727

728
checkbounds_indices(::Type{Bool}, inds::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, inds))
2,815,107✔
729

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

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

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

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

746
julia> checkindex(Bool, 1:20, 21)
747
false
748
```
749
"""
750
checkindex(::Type{Bool}, inds, i) = throw(ArgumentError(LazyString("unable to check bounds for indices of type ", typeof(i))))
6✔
751
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
25,558,469✔
752
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
9,203,450✔
753
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
5,942,348,762✔
754
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
×
755
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
×
756
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::AbstractRange) =
507,111,150✔
757
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
758
# range like indices with cheap `extrema`
759
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::LinearIndices) =
435✔
760
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
761

762
function checkindex(::Type{Bool}, inds, I::AbstractArray)
763
    @inline
25,031✔
764
    b = true
25,031✔
765
    for i in I
112,623✔
766
        b &= checkindex(Bool, inds, i)
20,927,286✔
767
    end
20,944,386✔
768
    b
106,935✔
769
end
770

771
# See also specializations in multidimensional
772

773
## Constructors ##
774

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

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

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

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

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

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

800
```jldoctest; filter = r"[01]"
801
julia> similar(trues(10,10), 2)
802
2-element BitVector:
803
 0
804
 0
805
```
806

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

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

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

836
to_shape(::Tuple{}) = ()
×
837
to_shape(dims::Dims) = dims
6✔
838
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
12,493,763✔
839
# each dimension
840
to_shape(i::Int) = i
11,947,500✔
841
to_shape(i::Integer) = Int(i)
137,906✔
842
to_shape(r::AbstractOneTo) = _to_shape(last(r))
12,185,604✔
843
_to_shape(x::Integer) = to_shape(x)
12,084,974✔
844
_to_shape(x) = Int(x)
×
845
to_shape(r::AbstractUnitRange) = r
×
846

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

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

854
**Examples**:
855

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

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

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

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

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

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

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

882
# Examples
883

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

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

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

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

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

908
$(_DOCS_ALIASING_WARNING)
909

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

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

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

929
function copy!(dst::AbstractArray, src::AbstractArray)
4,565✔
930
    axes(dst) == axes(src) || throw(ArgumentError(
55,341✔
931
        "arrays must have the same axes for copy! (consider using `copyto!`)"))
932
    copyto!(dst, src)
56,634✔
933
end
934

935
## from general iterable to any array
936

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

941
function copyto!(dest::AbstractArray, src)
215,153✔
942
    destiter = eachindex(dest)
218,763✔
943
    y = iterate(destiter)
233,344✔
944
    for x in src
337,245✔
945
        y === nothing &&
1,289,404✔
946
            throw(ArgumentError("destination has fewer elements than required"))
947
        dest[y[1]] = x
1,289,401✔
948
        y = iterate(destiter, y[2])
2,465,872✔
949
    end
2,375,804✔
950
    return dest
218,757✔
951
end
952

953
function copyto!(dest::AbstractArray, dstart::Integer, src)
462✔
954
    i = Int(dstart)
531✔
955
    if haslength(src) && length(dest) > 0
531✔
956
        @boundscheck checkbounds(dest, i:(i + length(src) - 1))
516✔
957
        for x in src
555✔
958
            @inbounds dest[i] = x
4,038✔
959
            i += 1
4,038✔
960
        end
5,169✔
961
    else
962
        for x in src
18✔
963
            dest[i] = x
27✔
964
            i += 1
9✔
965
        end
9✔
966
    end
967
    return dest
519✔
968
end
969

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

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

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

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

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

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

1048
$(_DOCS_ALIASING_WARNING)
1049

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

1054
julia> y = zeros(7);
1055

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

1058
julia> y
1059
7-element Vector{Float64}:
1060
 1.0
1061
 0.0
1062
 3.0
1063
 0.0
1064
 5.0
1065
 0.0
1066
 0.0
1067
```
1068
"""
1069
function copyto!(dest::AbstractArray, src::AbstractArray)
11,165,323✔
1070
    isempty(src) && return dest
11,350,738✔
1071
    if dest isa BitArray
8,702,093✔
1072
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1073
        return _copyto_bitarray!(dest, src)
38,200✔
1074
    end
1075
    src′ = unalias(dest, src)
8,718,107✔
1076
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
8,708,001✔
1077
end
1078

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

1085
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
356,239✔
1086
    isempty(src) && return dest
8,949,309✔
1087
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
8,963,760✔
1088
    idf, isf = first(destinds), first(srcinds)
8,939,888✔
1089
    Δi = idf - isf
8,939,888✔
1090
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
8,948,160✔
1091
        throw(BoundsError(dest, srcinds))
1092
    if deststyle isa IndexLinear
8,939,867✔
1093
        if srcstyle isa IndexLinear
8,930,408✔
1094
            # Single-index implementation
1095
            @inbounds for i in srcinds
8,614,425✔
1096
                dest[i + Δi] = src[i]
134,495,183✔
1097
            end
260,329,354✔
1098
        else
1099
            # Dual-index implementation
1100
            i = idf - 1
329,331✔
1101
            @inbounds for a in src
658,302✔
1102
                dest[i+=1] = a
8,820,380✔
1103
            end
17,289,847✔
1104
        end
1105
    else
1106
        iterdest, itersrc = eachindex(dest), eachindex(src)
9,462✔
1107
        if iterdest == itersrc
9,927✔
1108
            # Shared-iterator implementation
1109
            for I in iterdest
993✔
1110
                @inbounds dest[I] = src[I]
18,035,047✔
1111
            end
36,038,549✔
1112
        else
1113
            # Dual-iterator implementation
1114
            for (Idest, Isrc) in zip(iterdest, itersrc)
17,652✔
1115
                @inbounds dest[Idest] = src[Isrc]
6,101,133✔
1116
            end
12,193,356✔
1117
        end
1118
    end
1119
    return dest
8,948,013✔
1120
end
1121

1122
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
288✔
1123
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
153,564,684✔
1124
end
1125

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

1132
function copyto!(dest::AbstractArray, dstart::Integer,
1,400,114✔
1133
                 src::AbstractArray, sstart::Integer,
1134
                 n::Integer)
1135
    n == 0 && return dest
1,400,114✔
1136
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
1,400,033✔
1137
        n," elements, but n should be non-negative")))
1138
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
1,400,051✔
1139
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
1,400,066✔
1140
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
1,400,003✔
1141
    src′ = unalias(dest, src)
1,400,009✔
1142
    @inbounds for i = 0:n-1
1,399,988✔
1143
        dest[dstart+i] = src′[sstart+i]
115,597,983✔
1144
    end
229,795,381✔
1145
    return dest
1,399,985✔
1146
end
1147

1148
function copy(a::AbstractArray)
427,248✔
1149
    @_propagate_inbounds_meta
1,102✔
1150
    copymutable(a)
440,988✔
1151
end
1152

1153
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
2,271✔
1154
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1155
    if length(ir_dest) != length(ir_src)
2,271✔
1156
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
3✔
1157
            length(ir_src)," and ",length(ir_dest),")")))
1158
    end
1159
    if length(jr_dest) != length(jr_src)
2,268✔
1160
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1161
            length(jr_src)," and ",length(jr_dest),")")))
1162
    end
1163
    @boundscheck checkbounds(B, ir_dest, jr_dest)
2,268✔
1164
    @boundscheck checkbounds(A, ir_src, jr_src)
2,268✔
1165
    A′ = unalias(B, A)
3,417✔
1166
    jdest = first(jr_dest)
2,268✔
1167
    for jsrc in jr_src
4,533✔
1168
        idest = first(ir_dest)
34,524✔
1169
        for isrc in ir_src
69,039✔
1170
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
537,768✔
1171
            idest += step(ir_dest)
537,768✔
1172
        end
1,041,012✔
1173
        jdest += step(jr_dest)
34,524✔
1174
    end
66,780✔
1175
    return B
2,268✔
1176
end
1177

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

1180
function copyto_axcheck!(dest, src)
15,391✔
1181
    _checkaxs(axes(dest), axes(src))
135,376✔
1182
    copyto!(dest, src)
192,149✔
1183
end
1184

1185
"""
1186
    copymutable(a)
1187

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

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

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

1211
zero(x::AbstractArray{T}) where {T<:Number} = fill!(similar(x, typeof(zero(T))), zero(T))
15,861✔
1212
zero(x::AbstractArray{S}) where {S<:Union{Missing, Number}} = fill!(similar(x, typeof(zero(S))), zero(S))
9✔
1213
zero(x::AbstractArray) = map(zero, x)
39✔
1214

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

1229
one(x::AbstractMatrix{T}) where {T} = _one(one(T), x)
582✔
1230
oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
96✔
1231

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

1235
# While the definitions for IndexLinear are all simple enough to inline on their
1236
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1237
# inlining.
1238
iterate_starting_state(A) = iterate_starting_state(A, IndexStyle(A))
85,629,037✔
1239
iterate_starting_state(A, ::IndexLinear) = firstindex(A)
85,322,827✔
1240
iterate_starting_state(A, ::IndexStyle) = (eachindex(A),)
306,210✔
1241
@inline iterate(A::AbstractArray, state = iterate_starting_state(A)) = _iterate_abstractarray(A, state)
4,172,343,876✔
1242
@inline function _iterate_abstractarray(A::AbstractArray, state::Tuple)
1243
    y = iterate(state...)
111,642,030✔
1244
    y === nothing && return nothing
107,274,152✔
1245
    A[y[1]], (state[1], tail(y)...)
107,030,750✔
1246
end
1247
@inline function _iterate_abstractarray(A::AbstractArray, state::Integer)
2,806✔
1248
    checkbounds(Bool, A, state) || return nothing
3,928,274,437✔
1249
    A[state], state + one(state)
3,677,378,921✔
1250
end
1251

1252
isempty(a::AbstractArray) = (length(a) == 0)
240,559,735✔
1253

1254

1255
## range conversions ##
1256

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

1264
## unsafe/pointer conversions ##
1265

1266
# note: the following type definitions don't mean any AbstractArray is convertible to
1267
# a data Ref. they just map the array element type to the pointer type for
1268
# convenience in cases that work.
1269
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
246,652,235✔
1270
function pointer(x::AbstractArray{T}, i::Integer) where T
309,011✔
1271
    @inline
16,893,250✔
1272
    pointer(x) + Int(_memory_offset(x, i))::Int
20,408,954✔
1273
end
1274

1275
# The distance from pointer(x) to the element at x[I...] in bytes
1276
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
20,177,219✔
1277
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
148,803✔
1278
    J = _to_subscript_indices(x, I...)
377,316✔
1279
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
1,151,370✔
1280
end
1281

1282
## Special constprop heuristics for getindex/setindex
1283
typename(typeof(function getindex end)).constprop_heuristic = Core.ARRAY_INDEX_HEURISTIC
1284
typename(typeof(function setindex! end)).constprop_heuristic = Core.ARRAY_INDEX_HEURISTIC
1285

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

1298
Return a subset of array `A` as selected by the indices `inds`.
1299

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

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

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

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

1317
julia> getindex(A, 1)
1318
1
1319

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

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

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

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

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

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

1347
julia> getindex(A, A .> 2)
1348
2-element Vector{Int64}:
1349
 3
1350
 4
1351
```
1352
"""
1353
function getindex(A::AbstractArray, I...)
1,581,803✔
1354
    @_propagate_inbounds_meta
209,089,305✔
1355
    error_if_canonical_getindex(IndexStyle(A), A, I...)
209,089,305✔
1356
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
227,357,309✔
1357
end
1358
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1359
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
1,122,020,146✔
1360

1361
@inline unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
1,017✔
1362

1363
struct CanonicalIndexError <: Exception
1364
    func::String
1365
    type::Any
1366
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
57✔
1367
end
1368

1369
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
6✔
1370
    throw(CanonicalIndexError("getindex", typeof(A)))
1371
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
9✔
1372
    throw(CanonicalIndexError("getindex", typeof(A)))
1373
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
209,088,744✔
1374

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

1379
## IndexLinear Scalar indexing: canonical method is one Int
1380
_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)
79,251,702✔
1381
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
273✔
1382
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
1,026✔
1383
    @inline
3,786,787✔
1384
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
24,639,448✔
1385
    @inbounds r = getindex(A, _to_linear_index(A, I...))
24,639,219✔
1386
    r
3,786,616✔
1387
end
1388
_to_linear_index(A::AbstractArray, i::Integer) = i
152,985✔
1389
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
20,406,799✔
1390
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
1,686,111✔
1391
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
660,538,104✔
1392

1393
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1394
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
1395
    @inline
1,367,712✔
1396
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
1,367,949✔
1397
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
1,394,790✔
1398
    r
1,367,469✔
1399
end
1400
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
1401
    @_propagate_inbounds_meta
120,393,396✔
1402
    getindex(A, I...)
120,725,145✔
1403
end
1404
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
1,646,775✔
1405
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
6✔
1406
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1407
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
1,380✔
1408
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
36✔
1409
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1410
    @inline
241,467✔
1411
    J, Jrem = IteratorsMD.split(I, Val(N))
241,467✔
1412
    _to_subscript_indices(A, J, Jrem)
241,467✔
1413
end
1414
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
6✔
1415
    __to_subscript_indices(A, axes(A), J, Jrem)
1416
function __to_subscript_indices(A::AbstractArray,
1417
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1418
    @inline
6✔
1419
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
6✔
1420
end
1421
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
241,461✔
1422
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
92,667✔
1423
_remaining_size(::Tuple{Any}, t::Tuple) = t
6✔
1424
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
6✔
1425
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1426
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
1,646,775✔
1427

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

1431
"""
1432
    setindex!(A, X, inds...)
1433
    A[inds...] = X
1434

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

1438
$(_DOCS_ALIASING_WARNING)
1439

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

1444
julia> setindex!(A, [10, 20], [1, 2]);
1445

1446
julia> A[[3, 4]] = [30, 40];
1447

1448
julia> A
1449
2×2 Matrix{Float64}:
1450
 10.0  30.0
1451
 20.0  40.0
1452
```
1453
"""
1454
function setindex!(A::AbstractArray, v, I...)
6,782✔
1455
    @_propagate_inbounds_meta
9,025,810✔
1456
    error_if_canonical_setindex(IndexStyle(A), A, I...)
9,025,810✔
1457
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
33,511,417✔
1458
end
1459
function unsafe_setindex!(A::AbstractArray, v, I...)
1460
    @inline
2,196✔
1461
    @inbounds r = setindex!(A, v, I...)
2,196✔
1462
    r
2,190✔
1463
end
1464

1465
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
36✔
1466
    throw(CanonicalIndexError("setindex!", typeof(A)))
1467
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
6✔
1468
    throw(CanonicalIndexError("setindex!", typeof(A)))
1469
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
9,017,432✔
1470

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

1475
## IndexLinear Scalar indexing
1476
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
1,134,694✔
1477
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
1,872✔
1478
    @inline
461,318✔
1479
    @boundscheck checkbounds(A, I...)
24,142,836✔
1480
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
24,142,704✔
1481
    r
461,228✔
1482
end
1483

1484
# IndexCartesian Scalar indexing
1485
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
1486
    @_propagate_inbounds_meta
7,220,721✔
1487
    setindex!(A, v, I...)
7,220,865✔
1488
end
1489
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
1490
    @inline
70,359✔
1491
    @boundscheck checkbounds(A, I...)
70,386✔
1492
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
70,350✔
1493
    r
70,332✔
1494
end
1495

1496
_unsetindex!(A::AbstractArray, i::Integer) = _unsetindex!(A, to_index(i))
×
1497

1498
"""
1499
    parent(A)
1500

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

1506
# Examples
1507
```jldoctest
1508
julia> A = [1 2; 3 4]
1509
2×2 Matrix{Int64}:
1510
 1  2
1511
 3  4
1512

1513
julia> V = view(A, 1:2, :)
1514
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1515
 1  2
1516
 3  4
1517

1518
julia> parent(V)
1519
2×2 Matrix{Int64}:
1520
 1  2
1521
 3  4
1522
```
1523
"""
1524
function parent end
1525

1526
parent(a::AbstractArray) = a
5,112✔
1527

1528
## rudimentary aliasing detection ##
1529
"""
1530
    Base.unalias(dest, A)
1531

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

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

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

1542
See also [`Base.mightalias`](@ref).
1543
"""
1544
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
18,095,147✔
1545
unalias(dest, A::AbstractRange) = A
125,996,209✔
1546
unalias(dest, A) = A
9,393,640✔
1547

1548
"""
1549
    Base.unaliascopy(A)
1550

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

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

1573
"""
1574
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1575

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

1578
By default, this simply checks if either of the arrays reference the same memory
1579
regions, as identified by their [`Base.dataids`](@ref).
1580
"""
1581
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B))
18,086,030✔
1582
mightalias(x, y) = false
×
1583

1584
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1585
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1586
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1587
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1588
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
17,621,187✔
1589
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
138,780✔
1590
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1591
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
10,179✔
1592
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
186,879✔
1593

1594
"""
1595
    Base.dataids(A::AbstractArray)
1596

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

1599
Custom arrays that would like to opt-in to aliasing detection of their component
1600
parts can specialize this method to return the concatenation of the `dataids` of
1601
their component parts.  A typical definition for an array that wraps a parent is
1602
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1603
"""
1604
dataids(A::AbstractArray) = (objectid(A),)
258,378✔
1605
dataids(A::Memory) = (UInt(A.ptr),)
35,329,971✔
1606
dataids(A::Array) = dataids(A.ref.mem)
24,349,227✔
1607
dataids(::AbstractRange) = ()
26,785✔
1608
dataids(x) = ()
42,963✔
1609

1610
## get (getindex with a default value) ##
1611

1612
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1613
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1614

1615
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
63✔
1616
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
24✔
1617
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
42✔
1618
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
12✔
1619
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
21✔
1620
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
24✔
1621

1622
function get!(X::AbstractVector{T}, A::AbstractVector, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
×
1623
    # 1d is not linear indexing
1624
    ind = findall(in(axes1(A)), I)
×
1625
    X[ind] = A[I[ind]]
×
1626
    Xind = axes1(X)
×
1627
    X[first(Xind):first(ind)-1] = default
×
1628
    X[last(ind)+1:last(Xind)] = default
×
1629
    X
×
1630
end
1631
function get!(X::AbstractArray{T}, A::AbstractArray, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
3✔
1632
    # Linear indexing
1633
    ind = findall(in(1:length(A)), I)
3✔
1634
    X[ind] = A[I[ind]]
15✔
1635
    fill!(view(X, 1:first(ind)-1), default)
18✔
1636
    fill!(view(X, last(ind)+1:length(X)), default)
3✔
1637
    X
3✔
1638
end
1639

1640
get(A::AbstractArray, I::AbstractRange, default) = get!(similar(A, typeof(default), index_shape(I)), A, I, default)
3✔
1641

1642
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
6✔
1643
    fill!(X, default)
216✔
1644
    dst, src = indcopy(size(A), I)
6✔
1645
    X[dst...] = A[src...]
6✔
1646
    X
6✔
1647
end
1648

1649
get(A::AbstractArray, I::RangeVecIntList, default) =
6✔
1650
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1651

1652
## structured matrix methods ##
1653
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
71,894✔
1654
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
1,605✔
1655

1656
## Concatenation ##
1657
eltypeof(x) = typeof(x)
47,379✔
1658
eltypeof(x::AbstractArray) = eltype(x)
44,555✔
1659

1660
promote_eltypeof() = error()
×
1661
promote_eltypeof(v1) = eltypeof(v1)
×
1662
promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2))
4,822✔
1663
promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...))
82,279✔
1664
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
21,037✔
1665
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
60✔
1666

1667
promote_eltype() = error()
×
1668
promote_eltype(v1) = eltype(v1)
×
1669
promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2))
6,028✔
1670
promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...))
1,545✔
1671
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
813✔
1672
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
3,340✔
1673

1674
#TODO: ERROR CHECK
1675
_cat(catdim::Int) = Vector{Any}()
3✔
1676

1677
typed_vcat(::Type{T}) where {T} = Vector{T}()
3✔
1678
typed_hcat(::Type{T}) where {T} = Vector{T}()
3✔
1679

1680
## cat: special cases
1681
vcat(X::T...) where {T}         = T[ X[i] for i=eachindex(X) ]
3,851✔
1682
vcat(X::T...) where {T<:Number} = T[ X[i] for i=eachindex(X) ]
1,043✔
1683
hcat(X::T...) where {T}         = T[ X[j] for _=1:1, j=eachindex(X) ]
150✔
1684
hcat(X::T...) where {T<:Number} = T[ X[j] for _=1:1, j=eachindex(X) ]
24,001,473✔
1685

1686
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
12✔
1687
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
6✔
1688
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
33✔
1689
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
87✔
1690

1691
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
15✔
1692
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
17✔
1693

1694
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1695
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1696
# but that solution currently fails (see #27188 and #27224)
1697
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1698

1699
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
2,389,032✔
1700
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
4,632,426✔
1701
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1702

1703
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
2,373,087✔
1704
    pos = 1
2,388,867✔
1705
    for k=1:Int(length(V))::Int
2,388,867✔
1706
        Vk = V[k]
2,393,360✔
1707
        p1 = pos + Int(length(Vk))::Int - 1
4,487,411✔
1708
        a[pos:p1] = Vk
17,411,432✔
1709
        pos = p1+1
2,393,195✔
1710
    end
2,397,523✔
1711
    a
2,388,867✔
1712
end
1713

1714
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
3,099✔
1715

1716
# Catch indexing errors like v[i +1] (instead of v[i+1] or v[i + 1]), where indexing is
1717
# interpreted as a typed concatenation. (issue #49676)
1718
typed_hcat(::AbstractArray, other...) = throw(ArgumentError("It is unclear whether you \
9✔
1719
    intend to perform an indexing operation or typed concatenation. If you intend to \
1720
    perform indexing (v[1 + 2]), adjust spacing or insert missing operator to clarify. \
1721
    If you intend to perform typed concatenation (T[1 2]), ensure that T is a type."))
1722

1723

1724
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
900✔
1725
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
819✔
1726

1727
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
3,111✔
1728
    nargs = length(A)
3,117✔
1729
    nrows = size(A[1], 1)
3,117✔
1730
    ncols = 0
3,117✔
1731
    dense = true
3,117✔
1732
    for j = 1:nargs
3,117✔
1733
        Aj = A[j]
6,423✔
1734
        if size(Aj, 1) != nrows
8,781✔
1735
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
9✔
1736
        end
1737
        dense &= isa(Aj,Array)
6,420✔
1738
        nd = ndims(Aj)
8,778✔
1739
        ncols += (nd==2 ? size(Aj,2) : 1)
7,860✔
1740
    end
9,726✔
1741
    B = similar(A[1], T, nrows, ncols)
3,114✔
1742
    pos = 1
3,114✔
1743
    if dense
3,114✔
1744
        for k=1:nargs
1,209✔
1745
            Ak = A[k]
2,490✔
1746
            n = length(Ak)
3,153✔
1747
            copyto!(B, pos, Ak, 1, n)
4,221✔
1748
            pos += n
2,490✔
1749
        end
3,771✔
1750
    else
1751
        for k=1:nargs
1,905✔
1752
            Ak = A[k]
3,927✔
1753
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
4,746✔
1754
            B[:, pos:p1] = Ak
5,133✔
1755
            pos = p1+1
3,927✔
1756
        end
5,541✔
1757
    end
1758
    return B
3,114✔
1759
end
1760

1761
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
201✔
1762
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
627✔
1763

1764
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1,020✔
1765
    nargs = length(A)
1,077✔
1766
    nrows = sum(a->size(a, 1), A)::Int
3,249✔
1767
    ncols = size(A[1], 2)
1,077✔
1768
    for j = 2:nargs
1,077✔
1769
        if size(A[j], 2) != ncols
1,158✔
1770
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
9✔
1771
        end
1772
    end
1,173✔
1773
    B = similar(A[1], T, nrows, ncols)
1,074✔
1774
    pos = 1
1,074✔
1775
    for k=1:nargs
1,074✔
1776
        Ak = A[k]
2,169✔
1777
        p1 = pos+size(Ak,1)::Int-1
2,718✔
1778
        B[pos:p1, :] = Ak
2,337✔
1779
        pos = p1+1
2,169✔
1780
    end
3,264✔
1781
    return B
1,074✔
1782
end
1783

1784
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
4,633,482✔
1785

1786
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
21✔
1787
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1788

1789
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
18✔
1790
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1791

1792
## cat: general case
1793

1794
# helper functions
1795
cat_size(A) = (1,)
68,078✔
1796
cat_size(A::AbstractArray) = size(A)
49,890✔
1797
cat_size(A, d) = 1
×
1798
cat_size(A::AbstractArray, d) = size(A, d)
532,659✔
1799

1800
cat_length(::Any) = 1
×
1801
cat_length(a::AbstractArray) = length(a)
9,420✔
1802

1803
cat_ndims(a) = 0
×
1804
cat_ndims(a::AbstractArray) = ndims(a)
10,341✔
1805

1806
cat_indices(A, d) = OneTo(1)
68,081✔
1807
cat_indices(A::AbstractArray, d) = axes(A, d)
54,459✔
1808

1809
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
21,928✔
1810
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
×
1811
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
5,756✔
1812
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
×
1813
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
3,327✔
1814
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
×
1815

1816
# These are for backwards compatibility (even though internal)
1817
cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
×
1818
function cat_shape(dims, shapes::Tuple)
12✔
1819
    out_shape = ()
12✔
1820
    for s in shapes
12✔
1821
        out_shape = _cshp(1, dims, out_shape, s)
54✔
1822
    end
45✔
1823
    return out_shape
12✔
1824
end
1825
# The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1826
cat_size_shape(dims) = ntuple(Returns(0), Val(length(dims)))
×
1827
@inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
27,948✔
1828
_cat_size_shape(dims, shape) = shape
3,850✔
1829
@inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
90,363✔
1830

1831
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
881✔
1832
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
42✔
1833
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
609✔
1834
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
759✔
1835
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1836
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
6,819✔
1837
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1838
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
1839
    _cs(ndim, shape[1], 1)
69✔
1840
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
57✔
1841
end
1842
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
1843
    next = _cs(ndim, shape[1], nshape[1])
423✔
1844
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
423✔
1845
end
1846
@inline function _cshp(ndim::Int, dims, shape, nshape)
259✔
1847
    a = shape[1]
92,870✔
1848
    b = nshape[1]
92,870✔
1849
    next = dims[1] ? a + b : _cs(ndim, a, b)
93,745✔
1850
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
92,960✔
1851
end
1852

1853
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,548✔
1854
    "mismatch in dimension $d (expected $a got $b)")))
1855

1856
dims2cat(::Val{dims}) where dims = dims2cat(dims)
1,075✔
1857
function dims2cat(dims)
16✔
1858
    if any(≤(0), dims)
8,311✔
1859
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
6✔
1860
    end
1861
    ntuple(in(dims), maximum(dims))
5,959✔
1862
end
1863

1864
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
25,011✔
1865

1866
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
23,750✔
1867
    catdims = dims2cat(dims)
30,008✔
1868
    shape = cat_size_shape(catdims, X...)
27,948✔
1869
    A = cat_similar(X[1], T, shape)
27,567✔
1870
    if count(!iszero, catdims)::Int > 1
27,557✔
1871
        fill!(A, zero(T))
2,373✔
1872
    end
1873
    return __cat(A, shape, catdims, X...)
27,858✔
1874
end
1875
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1876
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1877
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1878

1879
# Why isn't this called `__cat!`?
1880
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(Returns(0), length(shape)), X...)
29,394✔
1881

1882
function __cat_offset!(A, shape, catdims, offsets, x, X...)
108,150✔
1883
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1884
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
253,017✔
1885
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
118,046✔
1886
end
1887
__cat_offset!(A, shape, catdims, offsets) = A
27,563✔
1888

1889
function __cat_offset1!(A, shape, catdims, offsets, x)
338✔
1890
    inds = ntuple(length(offsets)) do i
118,800✔
1891
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
126,519✔
1892
    end
1893
    _copy_or_fill!(A, inds, x)
500,136✔
1894
    newoffsets = ntuple(length(offsets)) do i
118,052✔
1895
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
123,501✔
1896
    end
1897
    return newoffsets
117,901✔
1898
end
1899

1900
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
68,076✔
1901
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
431,952✔
1902

1903
"""
1904
    vcat(A...)
1905

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

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

1912
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1913

1914
# Examples
1915
```jldoctest
1916
julia> v = vcat([1,2], [3,4])
1917
4-element Vector{Int64}:
1918
 1
1919
 2
1920
 3
1921
 4
1922

1923
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1924
true
1925

1926
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1927
true
1928

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

1932
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1933
3-element Vector{Float64}:
1934
 1.0
1935
 1.5
1936
 2.0
1937

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

1941
julia> vcat(two...)
1942
3×3 Matrix{Float64}:
1943
 10.0  20.0  30.0
1944
  4.0   5.0   6.0
1945
  7.0   8.0   9.0
1946

1947
julia> vs = [[1, 2], [3, 4], [5, 6]];
1948

1949
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1950
6-element Vector{Int64}:
1951
 1
1952
 2
1953
 3
1954
 4
1955
 5
1956
 6
1957

1958
julia> ans == collect(Iterators.flatten(vs))
1959
true
1960
```
1961
"""
1962
vcat(X...) = cat(X...; dims=Val(1))
1,668✔
1963
"""
1964
    hcat(A...)
1965

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

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

1973
See also [`vcat`](@ref), [`hvcat`](@ref).
1974

1975
# Examples
1976
```jldoctest
1977
julia> hcat([1,2], [3,4], [5,6])
1978
2×3 Matrix{Int64}:
1979
 1  3  5
1980
 2  4  6
1981

1982
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1983
1×7 Matrix{Int64}:
1984
 1  2  30  40  5  6  7
1985

1986
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1987
true
1988

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

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

1995
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
1996
2×6 Matrix{Float64}:
1997
 0.0  0.0  1.0  2.0  50.0  60.0
1998
 0.0  0.0  3.0  4.0  70.0  80.0
1999

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

2003
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
2004
0×3 Matrix{Int64}
2005

2006
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
2007
2×1 Matrix{Any}:
2008
 1.1
2009
 9.9
2010
```
2011
"""
2012
hcat(X...) = cat(X...; dims=Val(2))
30✔
2013

2014
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
1,425✔
2015
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
30✔
2016

2017
"""
2018
    cat(A...; dims)
2019

2020
Concatenate the input arrays along the dimensions specified in `dims`.
2021

2022
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
2023
a in A)`.
2024
Along other dimensions, all input arrays should have the same size,
2025
which will also be the size of the output array along those dimensions.
2026

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

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

2036
The keyword also accepts `Val(dims)`.
2037

2038
!!! compat "Julia 1.8"
2039
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
2040

2041
# Examples
2042

2043
Concatenate two arrays in different dimensions:
2044
```jldoctest
2045
julia> a = [1 2 3]
2046
1×3 Matrix{Int64}:
2047
 1  2  3
2048

2049
julia> b = [4 5 6]
2050
1×3 Matrix{Int64}:
2051
 4  5  6
2052

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

2058
julia> cat(a, b; dims=2)
2059
1×6 Matrix{Int64}:
2060
 1  2  3  4  5  6
2061

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

2068
# Extended Help
2069

2070
Concatenate 3D arrays:
2071
```jldoctest
2072
julia> a = ones(2, 2, 3);
2073

2074
julia> b = ones(2, 2, 4);
2075

2076
julia> c = cat(a, b; dims=3);
2077

2078
julia> size(c) == (2, 2, 7)
2079
true
2080
```
2081

2082
Concatenate arrays of different sizes:
2083
```jldoctest
2084
julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2)  # same as hcat
2085
2×6×1 Array{Float64, 3}:
2086
[:, :, 1] =
2087
 1.0  2.0  3.14159  10.0  10.0  10.0
2088
 3.0  4.0  3.14159  10.0  10.0  10.0
2089
```
2090

2091
Construct a block diagonal matrix:
2092
```
2093
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
2094
4×7 Matrix{Bool}:
2095
 1  0  0  0  0  0  0
2096
 0  1  1  0  0  0  0
2097
 0  1  1  0  0  0  0
2098
 0  0  0  1  1  1  1
2099
```
2100

2101
```
2102
julia> cat(1, [2], [3;;]; dims=Val(2))
2103
1×3 Matrix{Int64}:
2104
 1  2  3
2105
```
2106

2107
!!! note
2108
    `cat` does not join two strings, you may want to use `*`.
2109

2110
```jldoctest
2111
julia> a = "aaa";
2112

2113
julia> b = "bbb";
2114

2115
julia> cat(a, b; dims=1)
2116
2-element Vector{String}:
2117
 "aaa"
2118
 "bbb"
2119

2120
julia> cat(a, b; dims=2)
2121
1×2 Matrix{String}:
2122
 "aaa"  "bbb"
2123

2124
julia> a * b
2125
"aaabbb"
2126
```
2127
"""
2128
@inline cat(A...; dims) = _cat(dims, A...)
52,659✔
2129
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
2130
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
657✔
2131

2132
# The specializations for 1 and 2 inputs are important
2133
# especially when running with --inline=no, see #11158
2134
vcat(A::AbstractArray) = cat(A; dims=Val(1))
3✔
2135
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
15✔
2136
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
2137
vcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(1))
21,117✔
2138
hcat(A::AbstractArray) = cat(A; dims=Val(2))
3✔
2139
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
3✔
2140
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
3✔
2141
hcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(2))
18✔
2142

2143
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
3✔
2144
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2145
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
3✔
2146
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2147
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
3✔
2148
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
3✔
2149

2150
# 2d horizontal and vertical concatenation
2151

2152
# these are produced in lowering if splatting occurs inside hvcat
2153
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
12✔
2154
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
12✔
2155

2156
function hvcat(nbc::Int, as...)
30✔
2157
    # nbc = # of block columns
2158
    n = length(as)
30✔
2159
    mod(n,nbc) != 0 &&
60✔
2160
        throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
2161
    nbr = div(n,nbc)
27✔
2162
    hvcat(ntuple(Returns(nbc), nbr), as...)
27✔
2163
end
2164

2165
"""
2166
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2167

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

2173
# Examples
2174
```jldoctest
2175
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2176
(1, 2, 3, 4, 5, 6)
2177

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

2183
julia> hvcat((3,3), a,b,c,d,e,f)
2184
2×3 Matrix{Int64}:
2185
 1  2  3
2186
 4  5  6
2187

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

2194
julia> hvcat((2,2,2), a,b,c,d,e,f)
2195
3×2 Matrix{Int64}:
2196
 1  2
2197
 3  4
2198
 5  6
2199
julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f)
2200
true
2201
```
2202
"""
2203
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
1,065✔
2204
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray{T}...) where {T} = typed_hvcat(T, rows, xs...)
1,713✔
2205

2206
rows_to_dimshape(rows::Tuple{Vararg{Int}}) = all(==(rows[1]), rows) ? (length(rows), rows[1]) : (rows, (sum(rows),))
3,195✔
2207
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T = typed_hvncat(T, rows_to_dimshape(rows), true, as...)
2,901✔
2208

2209
hvcat(rows::Tuple{Vararg{Int}}) = []
3✔
2210
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2211

2212
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
3,947✔
2213
    nr = length(rows)
3,947✔
2214
    nc = rows[1]
3,947✔
2215

2216
    a = Matrix{T}(undef, nr, nc)
3,947✔
2217
    if length(a) != length(xs)
3,947✔
2218
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
6✔
2219
    end
2220
    k = 1
3,941✔
2221
    @inbounds for i=1:nr
3,941✔
2222
        if nc != rows[i]
10,604✔
2223
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
3✔
2224
        end
2225
        for j=1:nc
10,907✔
2226
            a[i,j] = xs[k]
28,697✔
2227
            k += 1
28,697✔
2228
        end
46,793✔
2229
    end
17,264✔
2230
    a
3,938✔
2231
end
2232

2233
function hvcat_fill!(a::Array, xs::Tuple)
1,837✔
2234
    nr, nc = size(a,1), size(a,2)
1,867✔
2235
    len = length(xs)
1,867✔
2236
    if nr*nc != len
1,867✔
2237
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
3✔
2238
    end
2239
    k = 1
1,864✔
2240
    for i=1:nr
1,873✔
2241
        @inbounds for j=1:nc
4,957✔
2242
            a[i,j] = xs[k]
29,131✔
2243
            k += 1
29,131✔
2244
        end
53,314✔
2245
    end
8,032✔
2246
    a
1,864✔
2247
end
2248

2249
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
520✔
2250
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
420✔
2251
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2252
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
9✔
2253

2254
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
1,546✔
2255
    nr = length(rows)
1,744✔
2256
    nc = rows[1]
1,744✔
2257
    for i = 2:nr
1,744✔
2258
        if nc != rows[i]
3,045✔
2259
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
6✔
2260
        end
2261
    end
4,022✔
2262
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
1,738✔
2263
end
2264

2265
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T = typed_hvncat(T, rows_to_dimshape(rows), true, as...)
465✔
2266

2267
## N-dimensional concatenation ##
2268

2269
"""
2270
    hvncat(dim::Int, row_first, values...)
2271
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2272
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2273

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

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

2287
# Examples
2288
```jldoctest
2289
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2290
(1, 2, 3, 4, 5, 6)
2291

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

2297
[:, :, 2] =
2298
 4  5  6
2299

2300
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2301
2×1×3 Array{Int64, 3}:
2302
[:, :, 1] =
2303
 1
2304
 2
2305

2306
[:, :, 2] =
2307
 3
2308
 4
2309

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

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

2319
[:, :, 2] =
2320
 3  4
2321

2322
[:, :, 3] =
2323
 5  6
2324

2325
julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2326
1×3×2 Array{Int64, 3}:
2327
[:, :, 1] =
2328
 1  2  3
2329

2330
[:, :, 2] =
2331
 4  5  6
2332
```
2333

2334
# Examples for construction of the arguments
2335
```
2336
[a b c ; d e f ;;;
2337
 g h i ; j k l ;;;
2338
 m n o ; p q r ;;;
2339
 s t u ; v w x]
2340
⇒ dims = (2, 3, 4)
2341

2342
[a b ; c ;;; d ;;;;]
2343
 ___   _     _
2344
 2     1     1 = elements in each row (2, 1, 1)
2345
 _______     _
2346
 3           1 = elements in each column (3, 1)
2347
 _____________
2348
 4             = elements in each 3d slice (4,)
2349
 _____________
2350
 4             = elements in each 4d slice (4,)
2351
⇒ shape = ((2, 1, 1), (3, 1), (4,), (4,)) with `row_first` = true
2352
```
2353
"""
2354
hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...)
798✔
2355
hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...)
255✔
2356

2357
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
84✔
2358
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
273✔
2359
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
300✔
2360
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2361
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2362
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
396✔
2363

2364

2365
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
3,168✔
2366
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
195✔
2367

2368
# 1-dimensional hvncat methods
2369

2370
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
×
2371
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2372
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
12✔
2373
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
12✔
2374
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2375
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
12✔
2376
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2377

2378
_typed_hvncat_0d_only_one() =
×
2379
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2380

2381
# `@constprop :aggressive` here to form constant `Val(dim)` type to get type stability
2382
@constprop :aggressive _typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters
228✔
2383

2384
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
195✔
2385
    N < 0 &&
195✔
2386
        throw(ArgumentError("concatenation dimension must be non-negative"))
2387
    return Array{T, N}(undef, ntuple(Returns(0), Val(N)))
192✔
2388
end
2389

2390
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
105✔
2391
    N < 0 &&
144✔
2392
        throw(ArgumentError("concatenation dimension must be non-negative"))
2393
    A = cat_similar(xs[1], T, (ntuple(Returns(1), Val(N - 1))..., length(xs)))
141✔
2394
    hvncat_fill!(A, false, xs)
141✔
2395
    return A
141✔
2396
end
2397

2398
function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
75✔
2399
    # optimization for arrays that can be concatenated by copying them linearly into the destination
2400
    # conditions: the elements must all have 1-length dimensions above N
2401
    length(as) > 0 ||
78✔
2402
        throw(ArgumentError("must have at least one element"))
2403
    N < 0 &&
78✔
2404
        throw(ArgumentError("concatenation dimension must be non-negative"))
2405
    for a ∈ as
72✔
2406
        ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) ||
165✔
2407
            return _typed_hvncat(T, (ntuple(Returns(1), Val(N - 1))..., length(as), 1), false, as...)
2408
            # the extra 1 is to avoid an infinite cycle
2409
    end
141✔
2410

2411
    nd = N
54✔
2412

2413
    Ndim = 0
54✔
2414
    for i ∈ eachindex(as)
54✔
2415
        Ndim += cat_size(as[i], N)
117✔
2416
        nd = max(nd, cat_ndims(as[i]))
117✔
2417
        for d ∈ 1:N - 1
99✔
2418
            cat_size(as[1], d) == cat_size(as[i], d) || throw(DimensionMismatch("mismatched size along axis $d in element $i"))
120✔
2419
        end
135✔
2420
    end
132✔
2421

2422
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(Returns(1), nd - N)...))
78✔
2423
    k = 1
42✔
2424
    for a ∈ as
42✔
2425
        for i ∈ eachindex(a)
81✔
2426
            A[k] = a[i]
114✔
2427
            k += 1
114✔
2428
        end
162✔
2429
    end
105✔
2430
    return A
42✔
2431
end
2432

2433
function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
42✔
2434
    length(as) > 0 ||
42✔
2435
        throw(ArgumentError("must have at least one element"))
2436
    N < 0 &&
42✔
2437
        throw(ArgumentError("concatenation dimension must be non-negative"))
2438
    nd = N
36✔
2439
    Ndim = 0
36✔
2440
    for i ∈ eachindex(as)
36✔
2441
        Ndim += cat_size(as[i], N)
90✔
2442
        nd = max(nd, cat_ndims(as[i]))
90✔
2443
        for d ∈ 1:N-1
60✔
2444
            cat_size(as[i], d) == 1 ||
108✔
2445
                throw(DimensionMismatch("all dimensions of element $i other than $N must be of length 1"))
2446
        end
84✔
2447
    end
60✔
2448

2449
    A = Array{T, nd}(undef, ntuple(Returns(1), Val(N - 1))..., Ndim, ntuple(Returns(1), nd - N)...)
18✔
2450

2451
    k = 1
12✔
2452
    for a ∈ as
12✔
2453
        if a isa AbstractArray
36✔
2454
            lena = length(a)
6✔
2455
            copyto!(A, k, a, 1, lena)
6✔
2456
            k += lena
6✔
2457
        else
2458
            A[k] = a
30✔
2459
            k += 1
30✔
2460
        end
2461
    end
48✔
2462
    return A
12✔
2463
end
2464

2465
# 0-dimensional cases for balanced and unbalanced hvncat method
2466

2467
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
6✔
2468
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
18✔
2469

2470

2471
# balanced dimensions hvncat methods
2472

2473
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
6✔
2474
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as::Number...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
21✔
2475

2476
function _typed_hvncat_1d(::Type{T}, ds::Int, ::Val{row_first}, as...) where {T, row_first}
63✔
2477
    lengthas = length(as)
66✔
2478
    ds > 0 ||
66✔
2479
        throw(ArgumentError("`dimsshape` argument must consist of positive integers"))
2480
    lengthas == ds ||
90✔
2481
        throw(ArgumentError("number of elements does not match `dimshape` argument; expected $ds, got $lengthas"))
2482
    if row_first
42✔
2483
        return _typed_hvncat(T, Val(2), as...)
12✔
2484
    else
2485
        return _typed_hvncat(T, Val(1), as...)
30✔
2486
    end
2487
end
2488

2489
function _typed_hvncat(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, xs::Number...) where {T, N}
144✔
2490
    all(>(0), dims) ||
192✔
2491
        throw(ArgumentError("`dims` argument must contain positive integers"))
2492
    A = Array{T, N}(undef, dims...)
96✔
2493
    lengtha = length(A)  # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations
96✔
2494
    lengthx = length(xs) # Cuts from 3 allocations to 1.
96✔
2495
    if lengtha != lengthx
96✔
2496
       throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)"))
×
2497
    end
2498
    hvncat_fill!(A, row_first, xs)
96✔
2499
    return A
96✔
2500
end
2501

2502
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
237✔
2503
    nr, nc = size(A, 1), size(A, 2)
237✔
2504
    na = prod(size(A)[3:end])
237✔
2505
    len = length(xs)
237✔
2506
    nrc = nr * nc
237✔
2507
    if nrc * na != len
237✔
2508
        throw(ArgumentError("argument count $(len) does not match specified shape $(size(A))"))
×
2509
    end
2510
    # putting these in separate functions leads to unnecessary allocations
2511
    if row_first
237✔
2512
        k = 1
57✔
2513
        for d ∈ 1:na
57✔
2514
            dd = nrc * (d - 1)
102✔
2515
            for i ∈ 1:nr
102✔
2516
                Ai = dd + i
147✔
2517
                for _ ∈ 1:nc
147✔
2518
                    @inbounds A[Ai] = xs[k]
336✔
2519
                    k += 1
336✔
2520
                    Ai += nr
336✔
2521
                end
525✔
2522
            end
192✔
2523
        end
102✔
2524
    else
2525
        for k ∈ eachindex(xs)
180✔
2526
            @inbounds A[k] = xs[k]
387✔
2527
        end
387✔
2528
    end
2529
end
2530

2531
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
3,009✔
2532
    # function barrier after calculating the max is necessary for high performance
2533
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
3,081✔
2534
    return _typed_hvncat_dims(T, (dims..., ntuple(Returns(1), nd - N)...), row_first, as)
3,081✔
2535
end
2536

2537
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
3,081✔
2538
    length(as) > 0 ||
3,081✔
2539
        throw(ArgumentError("must have at least one element"))
2540
    all(>(0), dims) ||
3,177✔
2541
        throw(ArgumentError("`dims` argument must contain positive integers"))
2542

2543
    d1 = row_first ? 2 : 1
2,985✔
2544
    d2 = row_first ? 1 : 2
2,985✔
2545

2546
    outdims = zeros(Int, N)
6,234✔
2547

2548
    # validate shapes for lowest level of concatenation
2549
    d = findfirst(>(1), dims)
4,242✔
2550
    if d !== nothing # all dims are 1
2,985✔
2551
        if row_first && d < 3
2,982✔
2552
            d = d == 1 ? 2 : 1
2,907✔
2553
        end
2554
        nblocks = length(as) ÷ dims[d]
2,982✔
2555
        for b ∈ 1:nblocks
2,982✔
2556
            offset = ((b - 1) * dims[d])
6,378✔
2557
            startelementi = offset + 1
6,378✔
2558
            for i ∈ offset .+ (2:dims[d])
9,438✔
2559
                for dd ∈ 1:N
4,143✔
2560
                    dd == d && continue
8,568✔
2561
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
4,530✔
2562
                        throw(DimensionMismatch("incompatible shape in element $i"))
18✔
2563
                    end
2564
                end
12,975✔
2565
            end
4,950✔
2566
        end
9,756✔
2567
    end
2568

2569
    # discover number of rows or columns
2570
    # d1 dimension is increased by 1 to appropriately handle 0-length arrays
2571
    for i ∈ 1:dims[d1]
2,967✔
2572
        outdims[d1] += cat_size(as[i], d1)
6,009✔
2573
    end
9,051✔
2574

2575
    # adjustment to handle 0-length arrays
2576
    first_dim_zero = outdims[d1] == 0
2,967✔
2577
    if first_dim_zero
2,967✔
2578
        outdims[d1] = dims[d1]
57✔
2579
    end
2580

2581
    currentdims = zeros(Int, N)
6,153✔
2582
    blockcount = 0
2,967✔
2583
    elementcount = 0
2,967✔
2584
    for i ∈ eachindex(as)
2,967✔
2585
        elementcount += cat_length(as[i])
11,871✔
2586
        currentdims[d1] += first_dim_zero ? 1 : cat_size(as[i], d1)
10,488✔
2587
        if currentdims[d1] == outdims[d1]
10,488✔
2588
            currentdims[d1] = 0
5,052✔
2589
            for d ∈ (d2, 3:N...)
5,052✔
2590
                currentdims[d] += cat_size(as[i], d)
5,271✔
2591
                if outdims[d] == 0 # unfixed dimension
5,271✔
2592
                    blockcount += 1
5,172✔
2593
                    if blockcount == dims[d]
5,172✔
2594
                        outdims[d] = currentdims[d]
3,069✔
2595
                        currentdims[d] = 0
3,069✔
2596
                        blockcount = 0
3,069✔
2597
                    else
2598
                        break
2,103✔
2599
                    end
2600
                else # fixed dimension
2601
                    if currentdims[d] == outdims[d] # end of dimension
99✔
2602
                        currentdims[d] = 0
60✔
2603
                    elseif currentdims[d] < outdims[d] # dimension in progress
39✔
2604
                        break
39✔
2605
                    else # exceeded dimension
2606
                        throw(DimensionMismatch("argument $i has too many elements along axis $d"))
×
2607
                    end
2608
                end
2609
            end
3,219✔
2610
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
5,436✔
2611
            throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
3✔
2612
        end
2613
    end
18,006✔
2614
    # restore 0-length adjustment
2615
    if first_dim_zero
2,964✔
2616
        outdims[d1] = 0
57✔
2617
    end
2618

2619
    outlen = prod(outdims)
5,928✔
2620
    elementcount == outlen ||
3,018✔
2621
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2622

2623
    # copy into final array
2624
    A = cat_similar(as[1], T, ntuple(i -> outdims[i], N))
5,820✔
2625
    # @assert all(==(0), currentdims)
2626
    outdims .= 0
5,931✔
2627
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
2,910✔
2628
    return A
2,910✔
2629
end
2630

2631

2632
# unbalanced dimensions hvncat methods
2633

2634
function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
57✔
2635
    length(shape[1]) > 0 ||
57✔
2636
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2637
    return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
39✔
2638
end
2639

2640
function _typed_hvncat(T::Type, shape::NTuple{N, Tuple}, row_first::Bool, as...) where {N}
351✔
2641
    # function barrier after calculating the max is necessary for high performance
2642
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
651✔
2643
    return _typed_hvncat_shape(T, (shape..., ntuple(Returns(shape[end]), nd - N)...), row_first, as)
627✔
2644
end
2645

2646
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
627✔
2647
    length(as) > 0 ||
627✔
2648
        throw(ArgumentError("must have at least one element"))
2649
    all(>(0), tuple((shape...)...)) ||
747✔
2650
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2651

2652
    d1 = row_first ? 2 : 1
507✔
2653
    d2 = row_first ? 1 : 2
507✔
2654

2655
    shapev = collect(shape) # saves allocations later
1,008✔
2656
    all(!isempty, shapev) ||
507✔
2657
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2658
    length(shapev[end]) == 1 ||
516✔
2659
        throw(ArgumentError("last level of shape must contain only one integer"))
2660
    shapelength = shapev[end][1]
498✔
2661
    lengthas = length(as)
498✔
2662
    shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)"))
498✔
2663
    # discover dimensions
2664
    nd = max(N, cat_ndims(as[1]))
498✔
2665
    outdims = fill(-1, nd)
1,260✔
2666
    currentdims = zeros(Int, nd)
1,260✔
2667
    blockcounts = zeros(Int, nd)
1,260✔
2668
    shapepos = ones(Int, nd)
1,260✔
2669

2670
    elementcount = 0
498✔
2671
    for i ∈ eachindex(as)
498✔
2672
        elementcount += cat_length(as[i])
2,706✔
2673
        wasstartblock = false
2,184✔
2674
        for d ∈ 1:N
2,184✔
2675
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
5,274✔
2676
            dsize = cat_size(as[i], ad)
6,489✔
2677
            blockcounts[d] += 1
5,274✔
2678

2679
            if d == 1 || i == 1 || wasstartblock
8,364✔
2680
                currentdims[d] += dsize
3,891✔
2681
            elseif dsize != cat_size(as[i - 1], ad)
1,506✔
2682
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
24✔
2683
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2684
            end
2685

2686
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
5,250✔
2687

2688
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
5,250✔
2689
            if isendblock
5,250✔
2690
                if outdims[d] == -1
1,890✔
2691
                    outdims[d] = currentdims[d]
1,044✔
2692
                elseif outdims[d] != currentdims[d]
846✔
2693
                    throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
120✔
2694
                                             expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2695
                end
2696
                currentdims[d] = 0
1,770✔
2697
                blockcounts[d] = 0
1,770✔
2698
                shapepos[d] += 1
1,770✔
2699
                d > 1 && (blockcounts[d - 1] == 0 ||
1,773✔
2700
                    throw(DimensionMismatch("shape in level $d is inconsistent; level counts must nest \
2701
                                             evenly into each other")))
2702
            end
2703
        end
8,217✔
2704
    end
3,723✔
2705

2706
    outlen = prod(outdims)
702✔
2707
    elementcount == outlen ||
351✔
2708
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2709

2710
    if row_first
351✔
2711
        outdims[1], outdims[2] = outdims[2], outdims[1]
339✔
2712
    end
2713

2714
    # @assert all(==(0), currentdims)
2715
    # @assert all(==(0), blockcounts)
2716

2717
    # copy into final array
2718
    A = cat_similar(as[1], T, ntuple(i -> outdims[i], nd))
702✔
2719
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
351✔
2720
    return A
351✔
2721
end
2722

2723
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int},
3,261✔
2724
                              d1::Int, d2::Int, as::Tuple) where {T, N}
2725
    N > 1 || throw(ArgumentError("dimensions of the destination array must be at least 2"))
3,261✔
2726
    length(scratch1) == length(scratch2) == N ||
3,261✔
2727
        throw(ArgumentError("scratch vectors must have as many elements as the destination array has dimensions"))
2728
    0 < d1 < 3 &&
3,261✔
2729
    0 < d2 < 3 &&
2730
    d1 != d2 ||
2731
        throw(ArgumentError("d1 and d2 must be either 1 or 2, exclusive."))
2732
    outdims = size(A)
3,261✔
2733
    offsets = scratch1
3,261✔
2734
    inneroffsets = scratch2
3,261✔
2735
    for a ∈ as
3,261✔
2736
        if isa(a, AbstractArray)
11,700✔
2737
            for ai ∈ a
12,876✔
2738
                @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
397,932✔
2739
                A[Ai] = ai
377,598✔
2740

2741
                @inbounds for j ∈ 1:N
377,598✔
2742
                    inneroffsets[j] += 1
436,860✔
2743
                    inneroffsets[j] < cat_size(a, j) && break
470,127✔
2744
                    inneroffsets[j] = 0
67,407✔
2745
                end
67,407✔
2746
            end
686,367✔
2747
        else
2748
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
3,084✔
2749
            A[Ai] = a
3,009✔
2750
        end
2751

2752
        @inbounds for j ∈ (d1, d2, 3:N...)
11,700✔
2753
            offsets[j] += cat_size(a, j)
17,901✔
2754
            offsets[j] < outdims[j] && break
17,901✔
2755
            offsets[j] = 0
9,483✔
2756
        end
9,483✔
2757
    end
11,700✔
2758
end
2759

2760
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
2761
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2762
    Ai = inneroffsets[1] + offsets[1] + 1
380,607✔
2763
    for j ∈ 2:nd
380,607✔
2764
        increment = inneroffsets[j] + offsets[j]
401,016✔
2765
        for k ∈ 1:j-1
401,016✔
2766
            increment *= outdims[k]
441,069✔
2767
        end
481,122✔
2768
        Ai += increment
401,016✔
2769
    end
421,425✔
2770
    Ai
380,607✔
2771
end
2772

2773
"""
2774
    stack(iter; [dims])
2775

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

2779
By default the axes of the elements are placed first,
2780
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2781
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2782

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

2787
The various [`cat`](@ref) functions also combine arrays. However, these all
2788
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2789
the arrays along new dimensions.
2790
They also accept arrays as separate arguments, rather than a single collection.
2791

2792
!!! compat "Julia 1.9"
2793
    This function requires at least Julia 1.9.
2794

2795
# Examples
2796
```jldoctest
2797
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2798

2799
julia> mat = stack(vecs)
2800
2×3 Matrix{Float32}:
2801
 1.0  30.0  500.0
2802
 2.0  40.0  600.0
2803

2804
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2805
true
2806

2807
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2808
true
2809

2810
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2811
2×4 Matrix{Int64}:
2812
  1   2   3   4
2813
 10  11  12  13
2814

2815
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2816
true
2817

2818
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2819
3×2 Matrix{Float32}:
2820
   1.0    2.0
2821
  30.0   40.0
2822
 500.0  600.0
2823

2824
julia> x = rand(3,4);
2825

2826
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2827
true
2828
```
2829

2830
Higher-dimensional examples:
2831

2832
```jldoctest
2833
julia> A = rand(5, 7, 11);
2834

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

2837
julia> (element = size(first(E)), container = size(E))
2838
(element = (5, 11), container = (7,))
2839

2840
julia> stack(E) |> size
2841
(5, 11, 7)
2842

2843
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2844
true
2845

2846
julia> A == stack(E; dims=2)
2847
true
2848

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

2851
julia> (element = size(first(M)), container = size(M))
2852
(element = (2, 3), container = (5, 7))
2853

2854
julia> stack(M) |> size  # keeps all dimensions
2855
(2, 3, 5, 7)
2856

2857
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2858
(35, 2, 3)
2859

2860
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2861
(14, 15)
2862
```
2863
"""
2864
stack(iter; dims::D=:) where {D} = _stack(dims, iter)
921✔
2865

2866
"""
2867
    stack(f, args...; [dims])
2868

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

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

2876
See also [`mapslices`](@ref), [`eachcol`](@ref).
2877

2878
# Examples
2879
```jldoctest
2880
julia> stack(c -> (c, c-32), "julia")
2881
2×5 Matrix{Char}:
2882
 'j'  'u'  'l'  'i'  'a'
2883
 'J'  'U'  'L'  'I'  'A'
2884

2885
julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2886
         vcat(row, row .* n, row ./ n)
2887
       end
2888
2×9 Matrix{Float64}:
2889
 1.0  2.0  3.0   10.0   20.0   30.0  0.1   0.2   0.3
2890
 4.0  5.0  6.0  400.0  500.0  600.0  0.04  0.05  0.06
2891
```
2892
"""
2893
stack(f, iter; dims::D=:) where {D} = _stack(dims, f(x) for x in iter)
72✔
2894
stack(f, xs, yzs...; dims::D=:) where {D} = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
6✔
2895

2896
_stack(dims::D, iter) where {D<:Union{Integer, Colon}} = _stack(dims, IteratorSize(iter), iter)
612✔
2897

2898
_stack(dims::D, ::IteratorSize, iter) where {D} = _stack(dims, collect(iter))
84✔
2899

2900
function _stack(dims::D, ::Union{HasShape, HasLength}, iter) where {D}
171✔
2901
    S = @default_eltype iter
471✔
2902
    T = S != Union{} ? eltype(S) : Any  # Union{} occurs for e.g. stack(1,2), postpone the error
471✔
2903
    if isconcretetype(T)
471✔
2904
        _typed_stack(dims, T, S, iter)
339✔
2905
    else  # Need to look inside, but shouldn't run an expensive iterator twice:
2906
        array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
201✔
2907
        isempty(array) && return _empty_stack(dims, T, S, iter)
189✔
2908
        T2 = mapreduce(eltype, promote_type, array)
180✔
2909
        _typed_stack(dims, T2, eltype(array), array)
180✔
2910
    end
2911
end
2912

2913
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
336✔
2914
    xit = iterate(A)
651✔
2915
    nothing === xit && return _empty_stack(:, T, S, A)
288✔
2916
    x1, _ = xit
288✔
2917
    ax1 = _iterator_axes(x1)
300✔
2918
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
300✔
2919
    off = firstindex(B)
285✔
2920
    len = length(x1)
303✔
2921
    while xit !== nothing
7,470✔
2922
        x, state = xit
7,206✔
2923
        _stack_size_check(x, ax1)
13,821✔
2924
        copyto!(B, off, x)
10,467✔
2925
        off += len
7,185✔
2926
        xit = iterate(A, state)
10,986✔
2927
    end
7,185✔
2928
    B
264✔
2929
end
2930

2931
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
29,658✔
2932
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
1,707✔
2933
_iterator_axes(x, ::IteratorSize) = axes(x)
27,951✔
2934

2935
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2936
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
234✔
2937
    _typed_stack(dims, T, S, IteratorSize(S), A)
2938
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
3✔
2939
    if dims == N+1
114✔
2940
        _typed_stack(:, T, S, A, (_vec_axis(A),))
12✔
2941
    else
2942
        _dim_stack(dims, T, S, A)
102✔
2943
    end
2944
end
2945
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
72✔
2946
    _dim_stack(dims, T, S, A)
2947

2948
_vec_axis(A, ax=_iterator_axes(A)) = length(ax) == 1 ? only(ax) : OneTo(prod(length, ax; init=1))
348✔
2949

2950
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
174✔
2951
    xit = Iterators.peel(A)
345✔
2952
    nothing === xit && return _empty_stack(dims, T, S, A)
174✔
2953
    x1, xrest = xit
174✔
2954
    ax1 = _iterator_axes(x1)
174✔
2955
    N1 = length(ax1)+1
171✔
2956
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
180✔
2957

2958
    newaxis = _vec_axis(A)
162✔
2959
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
936✔
2960
    B = similar(_ensure_array(x1), T, outax...)
168✔
2961

2962
    if dims == 1
162✔
2963
        _dim_stack!(Val(1), B, x1, xrest)
57✔
2964
    elseif dims == 2
105✔
2965
        _dim_stack!(Val(2), B, x1, xrest)
81✔
2966
    else
2967
        _dim_stack!(Val(dims), B, x1, xrest)
24✔
2968
    end
2969
    B
153✔
2970
end
2971

2972
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
138✔
2973
    before = ntuple(Returns(Colon()), dims - 1)
162✔
2974
    after = ntuple(Returns(Colon()), ndims(B) - dims)
162✔
2975

2976
    i = firstindex(B, dims)
162✔
2977
    copyto!(view(B, before..., i, after...), x1)
282✔
2978

2979
    for x in xrest
189✔
2980
        _stack_size_check(x, _iterator_axes(x1))
20,478✔
2981
        i += 1
10,746✔
2982
        @inbounds copyto!(view(B, before..., i, after...), x)
20,547✔
2983
    end
10,746✔
2984
end
2985

2986
@inline function _stack_size_check(x, ax1::Tuple)
492✔
2987
    if _iterator_axes(x) != ax1
34,806✔
2988
        uax1 = map(UnitRange, ax1)
30✔
2989
        uaxN = map(UnitRange, _iterator_axes(x))
30✔
2990
        throw(DimensionMismatch(
30✔
2991
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
2992
    end
2993
end
2994

2995
_ensure_array(x::AbstractArray) = x
327✔
2996
_ensure_array(x) = 1:0  # passed to similar, makes stack's output an Array
120✔
2997

2998
_empty_stack(_...) = throw(ArgumentError("`stack` on an empty collection is not allowed"))
9✔
2999

3000

3001
## Reductions and accumulates ##
3002

3003
function isequal(A::AbstractArray, B::AbstractArray)
691,459✔
3004
    if A === B return true end
833,155✔
3005
    if axes(A) != axes(B)
1,659,235✔
3006
        return false
5,406✔
3007
    end
3008
    for (a, b) in zip(A, B)
1,652,303✔
3009
        if !isequal(a, b)
298,585,095✔
3010
            return false
1,531✔
3011
        end
3012
    end
596,212,985✔
3013
    return true
825,370✔
3014
end
3015

3016
function cmp(A::AbstractVector, B::AbstractVector)
2,354✔
3017
    ai1, bi1 = firstindex(A), firstindex(B)
3,168✔
3018
    isequal(ai1, bi1) || return cmp(ai1, bi1)
3,180✔
3019
    for (a, b) in zip(A, B)
5,541✔
3020
        if !isequal(a, b)
4,815✔
3021
            return isless(a, b) ? -1 : 1
2,504✔
3022
        end
3023
    end
5,091✔
3024
    return cmp(length(A), length(B))
1,002✔
3025
end
3026

3027
"""
3028
    isless(A::AbstractArray{<:Any,0}, B::AbstractArray{<:Any,0})
3029

3030
Return `true` when the only element of `A` is less than the only element of `B`.
3031
"""
3032
function isless(A::AbstractArray{<:Any,0}, B::AbstractArray{<:Any,0})
63✔
3033
    isless(only(A), only(B))
84✔
3034
end
3035

3036
"""
3037
    isless(A::AbstractVector, B::AbstractVector)
3038

3039
Return `true` when `A` is less than `B`. Vectors are first compared by
3040
their starting indices, and then lexicographically by their elements.
3041
"""
3042
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
2,775✔
3043

3044
function (==)(A::AbstractArray, B::AbstractArray)
19,684,390✔
3045
    if axes(A) != axes(B)
42,636,246✔
3046
        return false
2,819,636✔
3047
    end
3048
    anymissing = false
19,785,662✔
3049
    for (a, b) in zip(A, B)
37,150,654✔
3050
        eq = (a == b)
1,015,947,621✔
3051
        if ismissing(eq)
912,639,726✔
3052
            anymissing = true
48✔
3053
        elseif !eq
1,013,214,068✔
3054
            return false
145,409✔
3055
        end
3056
    end
2,009,040,237✔
3057
    return anymissing ? missing : true
19,763,226✔
3058
end
3059

3060
# _sub2ind and _ind2sub
3061
# fallbacks
3062
function _sub2ind(A::AbstractArray, I...)
852✔
3063
    @inline
472,774,876✔
3064
    _sub2ind(axes(A), I...)
660,538,104✔
3065
end
3066

3067
function _ind2sub(A::AbstractArray, ind)
3068
    @inline
1,416,990✔
3069
    _ind2sub(axes(A), ind)
1,646,778✔
3070
end
3071

3072
# 0-dimensional arrays and indexing with []
3073
_sub2ind(::Tuple{}) = 1
×
3074
_sub2ind(::DimsInteger) = 1
×
3075
_sub2ind(::Indices) = 1
×
3076
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
9✔
3077

3078
# Generic cases
3079
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
3,393,289✔
3080
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
660,511,704✔
3081
# In 1d, there's a question of whether we're doing cartesian indexing
3082
# or linear indexing. Support only the former.
3083
_sub2ind(inds::Indices{1}, I::Integer...) =
3✔
3084
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3085
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
3086
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
3087

3088
_sub2ind_recurse(::Any, L, ind) = ind
501,789✔
3089
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,080✔
3090
    @inline
3,477✔
3091
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
11,572✔
3092
end
3093
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
2,796✔
3094
    @inline
37,895,482✔
3095
    r1 = inds[1]
37,898,587✔
3096
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
1,358,152,303✔
3097
end
3098

3099
nextL(L, l::Integer) = L*l
1,302,078✔
3100
nextL(L, r::AbstractUnitRange) = L*length(r)
692,843,728✔
3101
nextL(L, r::Slice) = L*length(r.indices)
×
3102
offsetin(i, l::Integer) = i-1
4,691,593✔
3103
offsetin(i, r::AbstractUnitRange) = i-first(r)
1,353,045,966✔
3104

3105
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
3106
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
3✔
3107
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
1,416,981✔
3108
_ind2sub(inds::Indices{1}, ind::Integer) =
3✔
3109
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3110
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
81✔
3111

3112
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3113
function _ind2sub_recurse(indslast::NTuple{1}, ind)
3114
    @inline
1,416,984✔
3115
    (_lookup(ind, indslast[1]),)
1,416,984✔
3116
end
3117
function _ind2sub_recurse(inds, ind)
3118
    @inline
2,455,151✔
3119
    r1 = inds[1]
2,455,151✔
3120
    indnext, indsub = divrem(ind, _indexlength(r1))
2,455,151✔
3121
    (_lookup(indsub, r1), _ind2sub_recurse(tail(inds), indnext)...)
2,455,151✔
3122
end
3123

3124
_indexlength(d::Integer) = d
3✔
3125
_indexlength(r::AbstractUnitRange) = length(r)
2,455,148✔
3126
_lookup(ind, d::Integer) = ind+1
6✔
3127
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
3,872,129✔
3128

3129
# Vectorized forms
3130
function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
×
3131
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
×
3132
end
3133
_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3134
    _sub2ind_vecs(inds, I1, I...)
3135
_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3136
    _sub2ind_vecs(inds, I1, I...)
3137
function _sub2ind_vecs(inds, I::AbstractVector...)
×
3138
    I1 = I[1]
×
3139
    Iinds = axes1(I1)
×
3140
    for j = 2:length(I)
×
3141
        axes1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(axes1(I[j])))"))
×
3142
    end
×
3143
    Iout = similar(I1)
×
3144
    _sub2ind!(Iout, inds, Iinds, I)
×
3145
    Iout
×
3146
end
3147

3148
function _sub2ind!(Iout, inds, Iinds, I)
×
3149
    @noinline
×
3150
    for i in Iinds
×
3151
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3152
        Iout[i] = sub2ind_vec(inds, i, I)
×
3153
    end
×
3154
    Iout
×
3155
end
3156

3157
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3158
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3159
_sub2ind_vec(i) = ()
×
3160

3161
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3162
    t = ntuple(_->similar(ind),Val(N))
×
3163
    for (i,idx) in pairs(IndexLinear(), ind)
×
3164
        sub = _ind2sub(inds, idx)
×
3165
        for j = 1:N
×
3166
            t[j][i] = sub[j]
×
3167
        end
×
3168
    end
×
3169
    t
×
3170
end
3171

3172
## iteration utilities ##
3173

3174
"""
3175
    foreach(f, c...) -> nothing
3176

3177
Call function `f` on each element of iterable `c`.
3178
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3179
any iterator is finished.
3180

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

3184
# Examples
3185
```jldoctest
3186
julia> tri = 1:3:7; res = Int[];
3187

3188
julia> foreach(x -> push!(res, x^2), tri)
3189

3190
julia> res
3191
3-element Vector{$(Int)}:
3192
  1
3193
 16
3194
 49
3195

3196
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3197
1 with a
3198
4 with b
3199
7 with c
3200
```
3201
"""
3202
foreach(f, itr) = (for x in itr; f(x); end; nothing)
1,166,806✔
3203
foreach(f, itr, itrs...) = (for z in zip(itr, itrs...); f(z...); end; nothing)
3✔
3204

3205
## map over arrays ##
3206

3207
## transform any set of dimensions
3208
## dims specifies which dimensions will be transformed. for example
3209
## dims==1:2 will call f on all slices A[:,:,...]
3210
"""
3211
    mapslices(f, A; dims)
3212

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

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

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

3222
# Examples
3223
```jldoctest
3224
julia> A = reshape(1:30,(2,5,3))
3225
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3226
[:, :, 1] =
3227
 1  3  5  7   9
3228
 2  4  6  8  10
3229

3230
[:, :, 2] =
3231
 11  13  15  17  19
3232
 12  14  16  18  20
3233

3234
[:, :, 3] =
3235
 21  23  25  27  29
3236
 22  24  26  28  30
3237

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

3240
julia> B = mapslices(f, A, dims=(1,2))
3241
1×4×3 Array{$Int, 3}:
3242
[:, :, 1] =
3243
 1  1  1  1
3244

3245
[:, :, 2] =
3246
 11  11  11  11
3247

3248
[:, :, 3] =
3249
 21  21  21  21
3250

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

3253
julia> B == stack(f2, eachslice(A, dims=3))
3254
true
3255

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

3258
julia> mapslices(g, A, dims=[1,3])
3259
1×5×1 Array{Rational{$Int}, 3}:
3260
[:, :, 1] =
3261
 1//21  3//23  1//5  7//27  9//29
3262

3263
julia> map(g, eachslice(A, dims=2))
3264
5-element Vector{Rational{$Int}}:
3265
 1//21
3266
 3//23
3267
 1//5
3268
 7//27
3269
 9//29
3270

3271
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3272
true
3273
```
3274

3275
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3276
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3277
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3278
values in the slice without affecting `A`.
3279
"""
3280
@constprop :aggressive function mapslices(f, A::AbstractArray; dims)
2,682✔
3281
    isempty(dims) && return map(f, A)
1,341✔
3282

3283
    for d in dims
1,701✔
3284
        d isa Integer || throw(ArgumentError("mapslices: dimension must be an integer, got $d"))
2,649✔
3285
        d >= 1 || throw(ArgumentError("mapslices: dimension must be ≥ 1, got $d"))
2,652✔
3286
        # Indexing a matrix M[:,1,:] produces a 1-column matrix, but dims=(1,3) here
3287
        # would otherwise ignore 3, and slice M[:,i]. Previously this gave error:
3288
        # BoundsError: attempt to access 2-element Vector{Any} at index [3]
3289
        d > ndims(A) && throw(ArgumentError("mapslices does not accept dimensions > ndims(A) = $(ndims(A)), got $d"))
2,646✔
3290
    end
2,661✔
3291
    dim_mask = ntuple(d -> d in dims, ndims(A))
5,970✔
3292

3293
    # Apply the function to the first slice in order to determine the next steps
3294
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
9,489✔
3295
    Aslice = A[idx1...]
1,614✔
3296
    r1 = f(Aslice)
1,590✔
3297

3298
    res1 = if r1 isa AbstractArray && ndims(r1) > 0
1,344✔
3299
        n = sum(dim_mask)
90✔
3300
        if ndims(r1) > n && any(ntuple(d -> size(r1,d+n)>1, ndims(r1)-n))
96✔
3301
            s = size(r1)[1:n]
6✔
3302
            throw(DimensionMismatch("mapslices cannot assign slice f(x) of size $(size(r1)) into output of size $s"))
3✔
3303
        end
3304
        r1
87✔
3305
    else
3306
        # If the result of f on a single slice is a scalar then we add singleton
3307
        # dimensions. When adding the dimensions, we have to respect the
3308
        # index type of the input array (e.g. in the case of OffsetArrays)
3309
        _res1 = similar(Aslice, typeof(r1), reduced_indices(Aslice, 1:ndims(Aslice)))
1,287✔
3310
        _res1[begin] = r1
1,242✔
3311
        _res1
2,442✔
3312
    end
3313

3314
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3315
    din = Ref(0)
1,329✔
3316
    Rsize = ntuple(ndims(A)) do d
2,583✔
3317
        if d in dims
9,717✔
3318
            axes(res1, din[] += 1)
2,631✔
3319
        else
3320
            axes(A,d)
2,421✔
3321
        end
3322
    end
3323
    R = similar(res1, Rsize)
1,332✔
3324

3325
    # Determine iteration space. It will be convenient in the loop to mask N-dimensional
3326
    # CartesianIndices, with some trivial dimensions:
3327
    itershape = ntuple(d -> d in dims ? Base.OneTo(1) : axes(A,d), ndims(A))
9,474✔
3328
    indices = Iterators.drop(CartesianIndices(itershape), 1)
1,329✔
3329

3330
    # That skips the first element, which we already have:
3331
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
10,062✔
3332
    concatenate_setindex!(R, res1, ridx...)
1,371✔
3333

3334
    # In some cases, we can re-use the first slice for a dramatic performance
3335
    # increase. The slice itself must be mutable and the result cannot contain
3336
    # any mutable containers. The following errs on the side of being overly
3337
    # strict (#18570 & #21123).
3338
    safe_for_reuse = isa(Aslice, StridedArray) &&
1,350✔
3339
                     (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number))
3340

3341
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
1,410✔
3342
    return R
1,329✔
3343
end
3344

3345
@noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
1,329✔
3346
    must_extend = any(dim_mask .& size(R) .> 1)
5,052✔
3347
    if safe_for_reuse
1,329✔
3348
        # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3349
        # so we can reuse Aslice
3350
        for I in indices
2,268✔
3351
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
33,591✔
3352
            _unsafe_getindex!(Aslice, A, idx...)
33,591✔
3353
            r = f(Aslice)
49,209✔
3354
            if r isa AbstractArray || must_extend
33,591✔
3355
                ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
267✔
3356
                R[ridx...] = r
534✔
3357
            else
3358
                ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
33,324✔
3359
                R[ridx...] = r
33,324✔
3360
            end
3361
        end
33,591✔
3362
    else
3363
        # we can't guarantee safety (#18524), so allocate new storage for each slice
3364
        for I in indices
390✔
3365
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
5,571✔
3366
            ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
5,571✔
3367
            concatenate_setindex!(R, f(A[idx...]), ridx...)
11,142✔
3368
        end
5,571✔
3369
    end
3370
end
3371

3372
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
5,553✔
3373
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
1,350✔
3374

3375
## 1 argument
3376

3377
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
6,431,825✔
3378
    for (i,j) in zip(eachindex(dest),eachindex(A))
14,118,690✔
3379
        val = f(@inbounds A[j])
18,746,479✔
3380
        @inbounds dest[i] = val
18,068,668✔
3381
    end
29,195,617✔
3382
    return dest
7,176,941✔
3383
end
3384

3385
# map on collections
3386
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
876,871✔
3387

3388
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
3,400✔
3389
mapany(f, itr) = Any[f(x) for x in itr]
×
3390

3391
"""
3392
    map(f, c...) -> collection
3393

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

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

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

3401
# Examples
3402
```jldoctest
3403
julia> map(x -> x * 2, [1, 2, 3])
3404
3-element Vector{Int64}:
3405
 2
3406
 4
3407
 6
3408

3409
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3410
3-element Vector{Int64}:
3411
 11
3412
 22
3413
 33
3414
```
3415
"""
3416
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
2,309✔
3417

3418
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
3✔
3419
map(f, ::AbstractSet) = error("map is not defined on sets")
3✔
3420

3421
## 2 argument
3422
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
1,098✔
3423
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
2,565✔
3424
        @inbounds a, b = A[j], B[k]
1,032,132✔
3425
        val = f(a, b)
1,032,132✔
3426
        @inbounds dest[i] = val
1,032,132✔
3427
    end
2,063,001✔
3428
    return dest
1,302✔
3429
end
3430

3431
## N argument
3432

3433
@inline ith_all(i, ::Tuple{}) = ()
20,490✔
3434
function ith_all(i, as)
3435
    @_propagate_inbounds_meta
61,470✔
3436
    return (as[1][i], ith_all(i, tail(as))...)
61,470✔
3437
end
3438

3439
function map_n!(f::F, dest::AbstractArray, As) where F
234✔
3440
    idxs = LinearIndices(dest)
234✔
3441
    if all(x -> LinearIndices(x) == idxs, As)
1,617✔
3442
        for i in idxs
225✔
3443
            @inbounds as = ith_all(i, As)
20,490✔
3444
            val = f(as...)
20,490✔
3445
            @inbounds dest[i] = val
20,490✔
3446
        end
40,758✔
3447
    else
3448
        for (i, Is...) in zip(eachindex(dest), map(eachindex, As)...)
18✔
3449
            as = ntuple(j->getindex(As[j], Is[j]), length(As))
18✔
3450
            val = f(as...)
6✔
3451
            dest[i] = val
6✔
3452
        end
6✔
3453
    end
3454
    return dest
234✔
3455
end
3456

3457
"""
3458
    map!(function, destination, collection...)
3459

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

3463
$(_DOCS_ALIASING_WARNING)
3464

3465
See also [`map`](@ref), [`foreach`](@ref), [`zip`](@ref), [`copyto!`](@ref).
3466

3467
# Examples
3468
```jldoctest
3469
julia> a = zeros(3);
3470

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

3473
julia> a
3474
3-element Vector{Float64}:
3475
 2.0
3476
 4.0
3477
 6.0
3478

3479
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3480
5-element Vector{$(Int)}:
3481
 101
3482
 103
3483
 105
3484
   0
3485
   0
3486
```
3487
"""
3488
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
222✔
3489
    @assert !isempty(As) # should dispatch to map!(f, A)
234✔
3490
    map_n!(f, dest, As)
234✔
3491
end
3492

3493
"""
3494
    map!(function, array)
3495

3496
Like [`map`](@ref), but stores the result in the same array.
3497
!!! compat "Julia 1.12"
3498
    This method requires Julia 1.12 or later. To support previous versions too,
3499
    use the equivalent `map!(function, array, array)`.
3500

3501
# Examples
3502
```jldoctest
3503
julia> a = [1 2 3; 4 5 6];
3504

3505
julia> map!(x -> x^3, a);
3506

3507
julia> a
3508
2×3 Matrix{$Int}:
3509
  1    8   27
3510
 64  125  216
3511
```
3512
"""
3513
map!(f::F, inout::AbstractArray) where F = map!(f, inout, inout)
2,685✔
3514

3515
"""
3516
    map(f, A::AbstractArray...) -> N-array
3517

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

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

3523
# Examples
3524
```
3525
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3526
2×2 Matrix{Rational{$Int}}:
3527
 1//4  2//3
3528
 3//2  4//1
3529

3530
julia> map(+, [1 2; 3 4], zeros(2,1))
3531
ERROR: DimensionMismatch
3532

3533
julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1))  # iterates until 3rd is exhausted
3534
3-element Vector{Float64}:
3535
   2.0
3536
  13.0
3537
 102.0
3538
```
3539
"""
3540
map(f, it, iters...) = collect(Generator(f, it, iters...))
101,537✔
3541

3542
# Generic versions of push! for AbstractVector
3543
# These are specialized further for Vector for faster resizing and setindexing
3544
function push!(a::AbstractVector{T}, item) where T
30✔
3545
    # convert first so we don't grow the array if the assignment won't work
3546
    itemT = item isa T ? item : convert(T, item)::T
63✔
3547
    new_length = length(a) + 1
39✔
3548
    resize!(a, new_length)
39✔
3549
    a[end] = itemT
39✔
3550
    return a
39✔
3551
end
3552

3553
# specialize and optimize the single argument case
3554
function push!(a::AbstractVector{Any}, @nospecialize x)
3✔
3555
    new_length = length(a) + 1
21✔
3556
    resize!(a, new_length)
21✔
3557
    a[end] = x
21✔
3558
    return a
21✔
3559
end
3560
function push!(a::AbstractVector{Any}, @nospecialize x...)
6✔
3561
    @_terminates_locally_meta
6✔
3562
    na = length(a)
6✔
3563
    nx = length(x)
6✔
3564
    resize!(a, na + nx)
6✔
3565
    e = lastindex(a) - nx
6✔
3566
    for i = 1:nx
6✔
3567
        a[e+i] = x[i]
15✔
3568
    end
24✔
3569
    return a
6✔
3570
end
3571

3572
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3573
# (note: must not cause a dispatch loop when 1-item case is not defined)
3574
push!(A, a, b) = push!(push!(A, a), b)
2,985✔
3575
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
6✔
3576
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3577
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
6✔
3578

3579
# sizehint! does nothing by default
3580
sizehint!(a::AbstractVector, _) = a
57✔
3581

3582
# The semantics of `collect` are weird. Better to write our own
3583
function rest(a::AbstractArray{T}, state...) where {T}
15✔
3584
    v = Vector{T}(undef, 0)
33✔
3585
    # assume only very few items are taken from the front
3586
    sizehint!(v, length(a))
33✔
3587
    return foldl(push!, Iterators.rest(a, state...), init=v)
33✔
3588
end
3589

3590
## keepat! ##
3591

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

3594
function _keepat!(a::AbstractVector, inds)
21✔
3595
    local prev
33✔
3596
    i = firstindex(a)
33✔
3597
    for k in inds
51✔
3598
        if @isdefined(prev)
102✔
3599
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
81✔
3600
        end
3601
        ak = a[k] # must happen even when i==k for bounds checking
105✔
3602
        if i != k
87✔
3603
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
39✔
3604
        end
3605
        prev = k
87✔
3606
        i = nextind(a, i)
87✔
3607
    end
150✔
3608
    deleteat!(a, i:lastindex(a))
33✔
3609
    return a
18✔
3610
end
3611

3612
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
474✔
3613
    length(m) == length(a) || throw(BoundsError(a, m))
483✔
3614
    j = firstindex(a)
471✔
3615
    for i in eachindex(a, m)
931✔
3616
        @inbounds begin
2,842✔
3617
            if m[i]
2,842✔
3618
                i == j || (a[j] = a[i])
2,934✔
3619
                j = nextind(a, j)
2,698✔
3620
            end
3621
        end
3622
    end
5,218✔
3623
    deleteat!(a, j:lastindex(a))
471✔
3624
end
3625

3626
"""
3627
    circshift!(a::AbstractVector, shift::Integer)
3628

3629
Circularly shift, or rotate, the data in vector `a` by `shift` positions.
3630

3631
# Examples
3632

3633
```jldoctest
3634
julia> circshift!([1, 2, 3, 4, 5], 2)
3635
5-element Vector{Int64}:
3636
 4
3637
 5
3638
 1
3639
 2
3640
 3
3641

3642
julia> circshift!([1, 2, 3, 4, 5], -2)
3643
5-element Vector{Int64}:
3644
 3
3645
 4
3646
 5
3647
 1
3648
 2
3649
```
3650
"""
3651
function circshift!(a::AbstractVector, shift::Integer)
3,369✔
3652
    n = length(a)
3,423✔
3653
    n == 0 && return a
3,423✔
3654
    shift = mod(shift, n)
6,834✔
3655
    shift == 0 && return a
3,417✔
3656
    l = lastindex(a)
2,241✔
3657
    reverse!(a, firstindex(a), l-shift)
2,241✔
3658
    reverse!(a, l-shift+1, lastindex(a))
2,241✔
3659
    reverse!(a)
2,241✔
3660
    return a
2,241✔
3661
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