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

JuliaLang / julia / 1652

20 Apr 2026 08:38PM UTC coverage: 77.962% (+0.3%) from 77.623%
1652

push

buildkite

web-flow
codegen: Propagate `ipo_purity_bits` to LLVM function attributes (#61394)

Translate Julia's inferred effects (consistent, effect_free, nothrow,
terminates, notaskstate) into LLVM function attributes so that
middle-end passes like GVN, LICM, and DSE can exploit them.

The key design insight is that GC interactions don't need to be visible
before GC lowering. Call-site declarations get optimistic memory
attributes (e.g. memory(argmem: read)) that enable pre-GC optimizations,
then LateLowerGCFrame widens them to memory(readwrite) before safepoint
analysis so post-GC passes see correct semantics.

Attributes added:
- nounwind: for nothrow functions (with uwtable(async) on definitions
  to preserve .eh_frame for stack scanning)
- mustprogress: for terminating functions
- willreturn: for nothrow+terminating functions
- memory(argmem: read): for consistent+effect_free functions with no
  user-facing pointer arguments (call-site declarations only)
- readnone on gcstack param: for notaskstate functions, so LICM can
  hoist pure calls past heap stores
- "julia.safepoint" marker: on all call-site declarations, used by
  LateLowerGCFrame to identify and widen optimistic attrs

LateLowerGCFrame strips all optimistic attributes (memory effects,
readnone on gcstack) from both call instructions and function
declarations before safepoint analysis runs.

Previously explored in #47844

Developed with Claude

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Gabriel Baraldi <28694980+gbaraldi@users.noreply.github.com>

65490 of 84002 relevant lines covered (77.96%)

23535049.1 hits per line

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

90.67
/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
133,957✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
14,388✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
21,102✔
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,993,670✔
44
    s = size(t)
200,550,064✔
45
    d <= length(s) ? s[d] : 1
200,539,828✔
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}
1,129✔
80
    @inline
26,451,093✔
81
    d::Integer <= N ? axes(A)[d] : OneTo(1)
26,591,747✔
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)
15,633✔
101
    @inline
2,862,345,204✔
102
    map(unchecked_oneto, size(A))
6,160,989,859✔
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)...)
616,263✔
116
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
423,040,754✔
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...)
27,948,588✔
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"))
441,245,680✔
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])
4,258,516,325✔
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,649✔
170
keys(a::AbstractVector) = LinearIndices(a)
6,816,843✔
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))
104,271,012✔
193
keytype(::Type{Union{}}, slurp...) = eltype(Union{})
×
194

195
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
6✔
196
keytype(A::Type{<:AbstractVector}) = Int
104,271,009✔
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,842✔
220
nextind(::AbstractArray, i::Integer) = Int(i)+1
110,186,644✔
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,456✔
244
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
×
245
eltype(x) = eltype(typeof(x))
200,370,344✔
246
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
309,157,472✔
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))
252,683,944✔
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
200,487,422✔
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,039,762✔
323

324
# eachindex iterates over all indices. IndexCartesian definitions are later.
325
eachindex(A::AbstractVector) = (@inline(); axes1(A))
41,924,204✔
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))
997,027✔
385

386
function eachindex(A::AbstractArray, B::AbstractArray)
21✔
387
    @inline
4,060✔
388
    eachindex(IndexStyle(A,B), A, B)
4,060✔
389
end
390
function eachindex(A::AbstractArray, B::AbstractArray...)
6✔
391
    @inline
5,005✔
392
    eachindex(IndexStyle(A,B...), A, B...)
5,005✔
393
end
394
eachindex(::IndexLinear, A::Union{Array, Memory}) = unchecked_oneto(length(A))
1,168,422,352✔
395
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
218,894,934✔
396
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
4,008,054,272✔
397
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
3✔
398
    @inline
10,868✔
399
    indsA = eachindex(IndexLinear(), A)
10,868✔
400
    indsBs = map(X -> eachindex(IndexLinear(), X), B)
26,738✔
401
    all(==(indsA), indsBs) ||
10,871✔
402
        throw_eachindex_mismatch_indices("indices", indsA, indsBs...)
403
    indsA
10,865✔
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)))
440,509,512✔
430
lastindex(a, d) = (@inline; last(axes(a, d)))
1,471,625✔
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)))
884,871,638✔
453
firstindex(a, d) = (@inline; first(axes(a, d)))
1,843,378✔
454

455
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
1,321,303✔
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,418✔
475
    x = iterate(itr)
11,973✔
476
    x === nothing && throw(ArgumentError("collection must be non-empty"))
8,737✔
477
    x[1]
8,732✔
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,522✔
509
    v[range(begin, length=min(n, checked_length(v)))]
4,616✔
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]
3,126,272✔
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,596,295✔
610
size_to_strides(s, d) = (s,)
4,458✔
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
749,167,267✔
684
    checkbounds_indices(Bool, axes(A), I)
957,127,063✔
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,442,081,501✔
692
    return checkindex(Bool, eachindex(IndexLinear(), A), i)
4,339,192,585✔
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})
9,484✔
723
    @inline
144,532,943✔
724
    return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &&
2,128,465,614✔
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))
45,872,018✔
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))
26,457,675✔
752
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
9,203,456✔
753
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
6,275,758,094✔
754
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
×
755
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
×
756
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::AbstractRange) =
543,073,075✔
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
23,708✔
764
    b = true
23,708✔
765
    for i in I
113,455✔
766
        b &= checkindex(Bool, inds, i)
21,022,565✔
767
    end
21,039,620✔
768
    b
107,767✔
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)
35,135✔
820
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, axes(a))
20,889✔
821
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, dims)
25,332,075✔
822
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, dims)
1,798✔
823
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, dims)
3,171,622✔
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))
26,111,517✔
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,253,551✔
835

836
to_shape(::Tuple{}) = ()
×
837
to_shape(dims::Dims) = dims
6✔
838
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
12,950,094✔
839
# each dimension
840
to_shape(i::Int) = i
12,341,066✔
841
to_shape(i::Integer) = Int(i)
188,400✔
842
to_shape(r::AbstractOneTo) = _to_shape(last(r))
12,633,970✔
843
_to_shape(x::Integer) = to_shape(x)
12,529,034✔
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))
47,027,220✔
873
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
47,041,845✔
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,876✔
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}()
646✔
896
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
198✔
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)
650✔
921
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
341,591✔
922
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
923
    if length(dst) != length(src)
341,654✔
924
        resize!(dst, length(src))
290,894✔
925
    end
926
    copyto!(dst, src)
637,735✔
927
end
928

929
function copy!(dst::AbstractArray, src::AbstractArray)
4,643✔
930
    axes(dst) == axes(src) || throw(ArgumentError(
55,456✔
931
        "arrays must have the same axes for copy! (consider using `copyto!`)"))
932
    copyto!(dst, src)
56,749✔
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)
252,986✔
942
    destiter = eachindex(dest)
258,312✔
943
    y = iterate(destiter)
272,400✔
944
    for x in src
407,837✔
945
        y === nothing &&
1,408,356✔
946
            throw(ArgumentError("destination has fewer elements than required"))
947
        dest[y[1]] = x
1,408,353✔
948
        y = iterate(destiter, y[2])
2,679,423✔
949
    end
2,595,171✔
950
    return dest
258,306✔
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,571✔
1001
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
2,580,571✔
1002
        ", elements, but n should be non-negative")))
1003
    n == 0 && return dest
2,580,568✔
1004
    dmax = dstart + n - 1
2,580,553✔
1005
    inds = LinearIndices(dest)
2,580,553✔
1006
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
5,161,100✔
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,547✔
1012
    for j = 1:(sstart-1)
2,580,541✔
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,538✔
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,538✔
1026
    i = Int(dstart)
2,580,538✔
1027
    @inbounds dest[i] = val
2,580,538✔
1028
    for val in Iterators.take(Iterators.rest(src, st), n-1)
5,161,065✔
1029
        i += 1
34,920,384✔
1030
        @inbounds dest[i] = val
34,920,384✔
1031
    end
67,260,242✔
1032
    i < dmax && throw(BoundsError(dest, i))
2,580,538✔
1033
    return dest
2,580,535✔
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)
12,259,266✔
1070
    isempty(src) && return dest
12,446,581✔
1071
    if dest isa BitArray
9,066,549✔
1072
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1073
        return _copyto_bitarray!(dest, src)
39,757✔
1074
    end
1075
    src′ = unalias(dest, src)
9,081,162✔
1076
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
9,071,646✔
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,124✔
1086
    isempty(src) && return dest
9,310,397✔
1087
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
9,324,782✔
1088
    idf, isf = first(destinds), first(srcinds)
9,300,302✔
1089
    Δi = idf - isf
9,300,302✔
1090
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
9,309,248✔
1091
        throw(BoundsError(dest, srcinds))
1092
    if deststyle isa IndexLinear
9,300,281✔
1093
        if srcstyle isa IndexLinear
9,290,849✔
1094
            # Single-index implementation
1095
            @inbounds for i in srcinds
8,975,087✔
1096
                dest[i + Δi] = src[i]
143,766,810✔
1097
            end
278,511,480✔
1098
        else
1099
            # Dual-index implementation
1100
            i = idf - 1
329,318✔
1101
            @inbounds for a in src
658,276✔
1102
                dest[i+=1] = a
8,795,216✔
1103
            end
17,239,532✔
1104
        end
1105
    else
1106
        iterdest, itersrc = eachindex(dest), eachindex(src)
9,435✔
1107
        if iterdest == itersrc
9,891✔
1108
            # Shared-iterator implementation
1109
            for I in iterdest
975✔
1110
                @inbounds dest[I] = src[I]
18,034,954✔
1111
            end
36,038,381✔
1112
        else
1113
            # Dual-iterator implementation
1114
            for (Idest, Isrc) in zip(iterdest, itersrc)
17,634✔
1115
                @inbounds dest[Idest] = src[Isrc]
6,101,124✔
1116
            end
12,193,347✔
1117
        end
1118
    end
1119
    return dest
9,309,101✔
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,748✔
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,441,458✔
1133
                 src::AbstractArray, sstart::Integer,
1134
                 n::Integer)
1135
    n == 0 && return dest
1,441,458✔
1136
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
1,441,370✔
1137
        n," elements, but n should be non-negative")))
1138
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
1,441,388✔
1139
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
1,441,403✔
1140
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
1,441,340✔
1141
    src′ = unalias(dest, src)
1,441,346✔
1142
    @inbounds for i = 0:n-1
1,441,337✔
1143
        dest[dstart+i] = src′[sstart+i]
112,023,127✔
1144
    end
222,604,332✔
1145
    return dest
1,441,322✔
1146
end
1147

1148
function copy(a::AbstractArray)
427,248✔
1149
    @_propagate_inbounds_meta
1,104✔
1150
    copymutable(a)
441,002✔
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,559✔
1179

1180
function copyto_axcheck!(dest, src)
15,684✔
1181
    _checkaxs(axes(dest), axes(src))
134,627✔
1182
    copyto!(dest, src)
191,440✔
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)
87✔
1206
    @_propagate_inbounds_meta
5,393✔
1207
    copyto!(similar(a), a)
467,224✔
1208
end
1209
copymutable(itr) = collect(itr)
255✔
1210
copymutable(a::Array) = copy(a)
56,070✔
1211

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

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

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

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

1236
# While the definitions for IndexLinear are all simple enough to inline on their
1237
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1238
# inlining.
1239
iterate_starting_state(A) = iterate_starting_state(A, IndexStyle(A))
98,424,059✔
1240
iterate_starting_state(A, ::IndexLinear) = firstindex(A)
98,113,291✔
1241
iterate_starting_state(A, ::IndexStyle) = (eachindex(A),)
310,768✔
1242
@inline iterate(A::AbstractArray, state = iterate_starting_state(A)) = _iterate_abstractarray(A, state)
4,360,963,237✔
1243
@inline function _iterate_abstractarray(A::AbstractArray, state::Tuple)
1244
    y = iterate(state...)
111,657,879✔
1245
    y === nothing && return nothing
107,234,695✔
1246
    A[y[1]], (state[1], tail(y)...)
106,986,706✔
1247
end
1248
@inline function _iterate_abstractarray(A::AbstractArray, state::Integer)
2,812✔
1249
    checkbounds(Bool, A, state) || return nothing
4,115,335,019✔
1250
    A[state], state + one(state)
3,814,592,877✔
1251
end
1252

1253
isempty(a::AbstractArray) = (length(a) == 0)
375,641,541✔
1254

1255

1256
## range conversions ##
1257

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

1265
## unsafe/pointer conversions ##
1266

1267
# note: the following type definitions don't mean any AbstractArray is convertible to
1268
# a data Ref. they just map the array element type to the pointer type for
1269
# convenience in cases that work.
1270
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
248,340,517✔
1271
function pointer(x::AbstractArray{T}, i::Integer) where T
314,680✔
1272
    @inline
16,268,184✔
1273
    pointer(x) + Int(_memory_offset(x, i))::Int
20,242,120✔
1274
end
1275

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1348
julia> getindex(A, A .> 2)
1349
2-element Vector{Int64}:
1350
 3
1351
 4
1352
```
1353
"""
1354
function getindex(A::AbstractArray, I...)
1,590,399✔
1355
    @_propagate_inbounds_meta
211,360,981✔
1356
    error_if_canonical_getindex(IndexStyle(A), A, I...)
211,360,981✔
1357
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
230,939,619✔
1358
end
1359
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1360
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
1,509,690,330✔
1361

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

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

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

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

1380
## IndexLinear Scalar indexing: canonical method is one Int
1381
_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)
81,660,357✔
1382
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
273✔
1383
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
1,026✔
1384
    @inline
3,714,413✔
1385
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
25,884,533✔
1386
    @inbounds r = getindex(A, _to_linear_index(A, I...))
25,884,305✔
1387
    r
3,714,242✔
1388
end
1389
_to_linear_index(A::AbstractArray, i::Integer) = i
153,015✔
1390
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
20,000,310✔
1391
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
1,629,614✔
1392
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
664,002,629✔
1393

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

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

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

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

1439
$(_DOCS_ALIASING_WARNING)
1440

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

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

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

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

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

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

1476
## IndexLinear Scalar indexing
1477
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
1,126,020✔
1478
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
1,872✔
1479
    @inline
462,771✔
1480
    @boundscheck checkbounds(A, I...)
26,943,607✔
1481
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
26,943,475✔
1482
    r
462,681✔
1483
end
1484

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

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

1499
"""
1500
    parent(A)
1501

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

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

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

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

1527
parent(a::AbstractArray) = a
5,073✔
1528

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

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

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

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

1543
See also [`Base.mightalias`](@ref).
1544
"""
1545
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
18,500,530✔
1546
unalias(dest, A::AbstractRange) = A
132,921,400✔
1547
unalias(dest, A) = A
9,943,924✔
1548

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

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

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

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

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

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

1585
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1586
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1587
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1588
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1589
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
18,024,890✔
1590
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
138,972✔
1591
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1592
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
10,179✔
1593
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
186,879✔
1594

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

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

1600
Custom arrays that would like to opt-in to aliasing detection of their component
1601
parts can specialize this method to return the concatenation of the `dataids` of
1602
their component parts.  A typical definition for an array that wraps a parent is
1603
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1604
"""
1605
dataids(A::AbstractArray) = (objectid(A),)
262,194✔
1606
dataids(A::Memory) = (UInt(A.ptr),)
36,130,372✔
1607
dataids(A::Array) = dataids(A.ref.mem)
24,786,329✔
1608
dataids(::AbstractRange) = ()
26,722✔
1609
dataids(x) = ()
43,172✔
1610

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

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

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

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

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

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

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

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

1657
## Concatenation ##
1658
eltypeof(x) = typeof(x)
47,466✔
1659
eltypeof(x::AbstractArray) = eltype(x)
44,602✔
1660

1661
promote_eltypeof() = error()
×
1662
promote_eltypeof(v1) = eltypeof(v1)
×
1663
promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2))
4,870✔
1664
promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...))
82,318✔
1665
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
21,042✔
1666
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
63✔
1667

1668
promote_eltype() = error()
×
1669
promote_eltype(v1) = eltype(v1)
×
1670
promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2))
5,912✔
1671
promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...))
1,515✔
1672
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
737✔
1673
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
3,250✔
1674

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

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

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

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

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

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

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

1704
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
2,373,093✔
1705
    pos = 1
2,388,876✔
1706
    for k=1:Int(length(V))::Int
2,388,876✔
1707
        Vk = V[k]
2,393,381✔
1708
        p1 = pos + Int(length(Vk))::Int - 1
4,487,438✔
1709
        a[pos:p1] = Vk
17,411,507✔
1710
        pos = p1+1
2,393,216✔
1711
    end
2,397,556✔
1712
    a
2,388,876✔
1713
end
1714

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

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

1724

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

1728
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
3,110✔
1729
    nargs = length(A)
3,116✔
1730
    nrows = size(A[1], 1)
3,116✔
1731
    ncols = 0
3,116✔
1732
    dense = true
3,116✔
1733
    for j = 1:nargs
3,116✔
1734
        Aj = A[j]
6,421✔
1735
        if size(Aj, 1) != nrows
8,779✔
1736
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
9✔
1737
        end
1738
        dense &= isa(Aj,Array)
6,418✔
1739
        nd = ndims(Aj)
8,776✔
1740
        ncols += (nd==2 ? size(Aj,2) : 1)
7,858✔
1741
    end
9,723✔
1742
    B = similar(A[1], T, nrows, ncols)
3,113✔
1743
    pos = 1
3,113✔
1744
    if dense
3,113✔
1745
        for k=1:nargs
1,209✔
1746
            Ak = A[k]
2,490✔
1747
            n = length(Ak)
3,153✔
1748
            copyto!(B, pos, Ak, 1, n)
4,221✔
1749
            pos += n
2,490✔
1750
        end
3,771✔
1751
    else
1752
        for k=1:nargs
1,904✔
1753
            Ak = A[k]
3,925✔
1754
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
4,744✔
1755
            B[:, pos:p1] = Ak
5,131✔
1756
            pos = p1+1
3,925✔
1757
        end
5,538✔
1758
    end
1759
    return B
3,113✔
1760
end
1761

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

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

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

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

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

1793
## cat: general case
1794

1795
# helper functions
1796
cat_size(A) = (1,)
68,136✔
1797
cat_size(A::AbstractArray) = size(A)
49,949✔
1798
cat_size(A, d) = 1
×
1799
cat_size(A::AbstractArray, d) = size(A, d)
132,998✔
1800

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

1804
cat_ndims(a) = 0
×
1805
cat_ndims(a::AbstractArray) = ndims(a)
10,344✔
1806

1807
cat_indices(A, d) = OneTo(1)
68,139✔
1808
cat_indices(A::AbstractArray, d) = axes(A, d)
54,518✔
1809

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

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

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

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

1857
dims2cat(::Val{dims}) where dims = dims2cat(dims)
1,129✔
1858
function dims2cat(dims)
2,329✔
1859
    if any(≤(0), dims)
8,365✔
1860
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
6✔
1861
    end
1862
    ntuple(in(dims), maximum(dims))
3,700✔
1863
end
1864

1865
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
25,067✔
1866

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

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

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

1890
function __cat_offset1!(A, shape, catdims, offsets, x)
338✔
1891
    inds = ntuple(length(offsets)) do i
118,980✔
1892
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
126,699✔
1893
    end
1894
    _copy_or_fill!(A, inds, x)
500,258✔
1895
    newoffsets = ntuple(length(offsets)) do i
118,169✔
1896
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
123,616✔
1897
    end
1898
    return newoffsets
118,009✔
1899
end
1900

1901
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
68,143✔
1902
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
432,007✔
1903

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2042
# Examples
2043

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

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

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

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

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

2069
# Extended Help
2070

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

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

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

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

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

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

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

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

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

2114
julia> b = "bbb";
2115

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

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

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

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

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

2151
# 2d horizontal and vertical concatenation
2152

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

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

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

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

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

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

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

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

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

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

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

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

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

2234
function hvcat_fill!(a::Array, xs::Tuple)
1,842✔
2235
    nr, nc = size(a,1), size(a,2)
1,872✔
2236
    len = length(xs)
1,872✔
2237
    if nr*nc != len
1,872✔
2238
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
3✔
2239
    end
2240
    k = 1
1,869✔
2241
    for i=1:nr
1,878✔
2242
        @inbounds for j=1:nc
4,965✔
2243
            a[i,j] = xs[k]
29,157✔
2244
            k += 1
29,157✔
2245
        end
53,358✔
2246
    end
8,043✔
2247
    a
1,869✔
2248
end
2249

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

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

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

2268
## N-dimensional concatenation ##
2269

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2365

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

2369
# 1-dimensional hvncat methods
2370

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

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

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

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

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

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

2410
    nd = N
54✔
2411

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

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

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

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

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

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

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

2469

2470
# balanced dimensions hvncat methods
2471

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

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

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

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

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

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

2542
    d1 = row_first ? 2 : 1
2,991✔
2543
    d2 = row_first ? 1 : 2
2,991✔
2544

2545
    outdims = zeros(Int, N)
6,246✔
2546

2547
    # validate shapes for lowest level of concatenation
2548
    d = findfirst(>(1), dims)
4,248✔
2549
    if d !== nothing # all dims are 1
2,991✔
2550
        if row_first && d < 3
2,988✔
2551
            d = d == 1 ? 2 : 1
2,913✔
2552
        end
2553
        nblocks = length(as) ÷ dims[d]
2,988✔
2554
        for b ∈ 1:nblocks
2,988✔
2555
            offset = ((b - 1) * dims[d])
6,390✔
2556
            startelementi = offset + 1
6,390✔
2557
            for i ∈ offset .+ (2:dims[d])
9,450✔
2558
                for dd ∈ 1:N
4,155✔
2559
                    dd == d && continue
8,592✔
2560
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
4,542✔
2561
                        throw(DimensionMismatch("incompatible shape in element $i"))
18✔
2562
                    end
2563
                end
13,011✔
2564
            end
4,962✔
2565
        end
9,774✔
2566
    end
2567

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

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

2580
    currentdims = zeros(Int, N)
6,165✔
2581
    blockcount = 0
2,973✔
2582
    elementcount = 0
2,973✔
2583
    for i ∈ eachindex(as)
2,973✔
2584
        elementcount += cat_length(as[i])
11,898✔
2585
        currentdims[d1] += first_dim_zero ? 1 : cat_size(as[i], d1)
10,512✔
2586
        if currentdims[d1] == outdims[d1]
10,512✔
2587
            currentdims[d1] = 0
5,064✔
2588
            for d ∈ (d2, 3:N...)
5,064✔
2589
                currentdims[d] += cat_size(as[i], d)
5,283✔
2590
                if outdims[d] == 0 # unfixed dimension
5,283✔
2591
                    blockcount += 1
5,184✔
2592
                    if blockcount == dims[d]
5,184✔
2593
                        outdims[d] = currentdims[d]
3,075✔
2594
                        currentdims[d] = 0
3,075✔
2595
                        blockcount = 0
3,075✔
2596
                    else
2597
                        break
2,109✔
2598
                    end
2599
                else # fixed dimension
2600
                    if currentdims[d] == outdims[d] # end of dimension
99✔
2601
                        currentdims[d] = 0
60✔
2602
                    elseif currentdims[d] < outdims[d] # dimension in progress
39✔
2603
                        break
39✔
2604
                    else # exceeded dimension
2605
                        throw(DimensionMismatch("argument $i has too many elements along axis $d"))
×
2606
                    end
2607
                end
2608
            end
3,225✔
2609
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
5,448✔
2610
            throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
3✔
2611
        end
2612
    end
18,048✔
2613
    # restore 0-length adjustment
2614
    if first_dim_zero
2,970✔
2615
        outdims[d1] = 0
57✔
2616
    end
2617

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

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

2630

2631
# unbalanced dimensions hvncat methods
2632

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

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

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

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

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

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

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

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

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

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

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

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

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

2724
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int}, d1::Int, d2::Int, as::Tuple) where {T, N}
3,261✔
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
    outdimsprod = cumprod(size(A))
3,261✔
2733
    offsets = scratch1
3,261✔
2734
    inneroffsets = scratch2
3,261✔
2735
    for a ∈ as
3,261✔
2736
        startindex = CartesianIndex(ntuple(i -> offsets[i] + 1, Val(N)))
23,394✔
2737
        if isa(a, AbstractArray)
11,697✔
2738
            if !isempty(a)
10,293✔
2739
                if length(a) > 4
9,726✔
2740
                    endindex = CartesianIndex(ntuple(i -> offsets[i] + cat_size(a, i), Val(N)))
13,413✔
2741
                    @inbounds A[startindex:endindex] = a
6,696✔
2742
                else
2743
                    for ai ∈ a
1,557✔
2744
                        @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdimsprod, N)
4,098✔
2745
                        @inbounds A[Ai] = ai
3,432✔
2746
                        @inbounds for j ∈ 1:N
3,432✔
2747
                            inneroffsets[j] += 1
5,703✔
2748
                            inneroffsets[j] < cat_size(a, j) && break
7,167✔
2749
                            inneroffsets[j] = 0
3,723✔
2750
                        end
7,155✔
2751
                    end
3,432✔
2752
                end
2753
            end
2754
        else
2755
            @inbounds A[startindex] = a
3,030✔
2756
        end
2757

2758
        @inbounds for i ∈ (d1, d2, 3:N...)
11,697✔
2759
            offsets[i] += cat_size(a, i)
17,856✔
2760
            offsets[i] < cat_size(A, i) && break
17,856✔
2761
            offsets[i] = 0
9,429✔
2762
        end
21,126✔
2763
    end
11,697✔
2764
end
2765

2766
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
2767
                                                outdimsprod::NTuple{N, Int}, nd::Int) where {N}
2768
    Ai = inneroffsets[1] + offsets[1] + 1
3,432✔
2769
    for j ∈ 2:nd
3,432✔
2770
        increment = inneroffsets[j] + offsets[j]
4,098✔
2771
        increment *= outdimsprod[j - 1]
4,098✔
2772
        Ai += increment
4,098✔
2773
    end
4,764✔
2774
    Ai
3,432✔
2775
end
2776

2777
"""
2778
    stack(iter; [dims])
2779

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

2783
By default the axes of the elements are placed first,
2784
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2785
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2786

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

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

2796
!!! compat "Julia 1.9"
2797
    This function requires at least Julia 1.9.
2798

2799
# Examples
2800
```jldoctest
2801
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2802

2803
julia> mat = stack(vecs)
2804
2×3 Matrix{Float32}:
2805
 1.0  30.0  500.0
2806
 2.0  40.0  600.0
2807

2808
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2809
true
2810

2811
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2812
true
2813

2814
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2815
2×4 Matrix{Int64}:
2816
  1   2   3   4
2817
 10  11  12  13
2818

2819
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2820
true
2821

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

2828
julia> x = rand(3,4);
2829

2830
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2831
true
2832
```
2833

2834
Higher-dimensional examples:
2835

2836
```jldoctest
2837
julia> A = rand(5, 7, 11);
2838

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

2841
julia> (element = size(first(E)), container = size(E))
2842
(element = (5, 11), container = (7,))
2843

2844
julia> stack(E) |> size
2845
(5, 11, 7)
2846

2847
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2848
true
2849

2850
julia> A == stack(E; dims=2)
2851
true
2852

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

2855
julia> (element = size(first(M)), container = size(M))
2856
(element = (2, 3), container = (5, 7))
2857

2858
julia> stack(M) |> size  # keeps all dimensions
2859
(2, 3, 5, 7)
2860

2861
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2862
(35, 2, 3)
2863

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

2870
"""
2871
    stack(f, args...; [dims])
2872

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

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

2880
See also [`mapslices`](@ref), [`eachcol`](@ref).
2881

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

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

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

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

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

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

2935
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
29,658✔
2936
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
1,707✔
2937
_iterator_axes(x, ::IteratorSize) = axes(x)
27,951✔
2938

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

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

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

2962
    newaxis = _vec_axis(A)
162✔
2963
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
936✔
2964
    B = similar(_ensure_array(x1), T, outax...)
168✔
2965

2966
    if dims == 1
162✔
2967
        _dim_stack!(Val(1), B, x1, xrest)
57✔
2968
    elseif dims == 2
105✔
2969
        _dim_stack!(Val(2), B, x1, xrest)
81✔
2970
    else
2971
        _dim_stack!(Val(dims), B, x1, xrest)
24✔
2972
    end
2973
    B
153✔
2974
end
2975

2976
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
138✔
2977
    before = ntuple(Returns(Colon()), dims - 1)
162✔
2978
    after = ntuple(Returns(Colon()), ndims(B) - dims)
162✔
2979

2980
    i = firstindex(B, dims)
162✔
2981
    copyto!(view(B, before..., i, after...), x1)
282✔
2982

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

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

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

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

3004

3005
## Reductions and accumulates ##
3006

3007
function isequal(A::AbstractArray, B::AbstractArray)
694,294✔
3008
    if A === B return true end
836,643✔
3009
    if axes(A) != axes(B)
1,666,213✔
3010
        return false
5,406✔
3011
    end
3012
    for (a, b) in zip(A, B)
1,659,280✔
3013
        if !isequal(a, b)
301,878,094✔
3014
            return false
1,460✔
3015
        end
3016
    end
602,554,220✔
3017
    return true
828,930✔
3018
end
3019

3020
function cmp(A::AbstractVector, B::AbstractVector)
2,350✔
3021
    ai1, bi1 = firstindex(A), firstindex(B)
3,196✔
3022
    isequal(ai1, bi1) || return cmp(ai1, bi1)
3,208✔
3023
    for (a, b) in zip(A, B)
5,597✔
3024
        if !isequal(a, b)
4,919✔
3025
            return isless(a, b) ? -1 : 1
2,548✔
3026
        end
3027
    end
5,243✔
3028
    return cmp(length(A), length(B))
1,002✔
3029
end
3030

3031
"""
3032
    isless(A::AbstractArray{<:Any,0}, B::AbstractArray{<:Any,0})
3033

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

3040
"""
3041
    isless(A::AbstractVector, B::AbstractVector)
3042

3043
Return `true` when `A` is less than `B`. Vectors are first compared by
3044
their starting indices, and then lexicographically by their elements.
3045
"""
3046
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
2,814✔
3047

3048
function (==)(A::AbstractArray, B::AbstractArray)
19,684,123✔
3049
    if axes(A) != axes(B)
42,699,766✔
3050
        return false
2,900,606✔
3051
    end
3052
    anymissing = false
19,895,584✔
3053
    for (a, b) in zip(A, B)
37,131,935✔
3054
        eq = (a == b)
1,015,798,926✔
3055
        if ismissing(eq)
912,679,423✔
3056
            anymissing = true
48✔
3057
        elseif !eq
1,013,129,590✔
3058
            return false
166,180✔
3059
        end
3060
    end
2,008,860,561✔
3061
    return anymissing ? missing : true
19,733,673✔
3062
end
3063

3064
# _sub2ind and _ind2sub
3065
# fallbacks
3066
function _sub2ind(A::AbstractArray, I...)
852✔
3067
    @inline
472,509,298✔
3068
    _sub2ind(axes(A), I...)
664,002,629✔
3069
end
3070

3071
function _ind2sub(A::AbstractArray, ind)
3072
    @inline
1,417,871✔
3073
    _ind2sub(axes(A), ind)
1,647,659✔
3074
end
3075

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

3082
# Generic cases
3083
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
32,164,037✔
3084
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
663,976,223✔
3085
# In 1d, there's a question of whether we're doing cartesian indexing
3086
# or linear indexing. Support only the former.
3087
_sub2ind(inds::Indices{1}, I::Integer...) =
3✔
3088
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3089
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
3090
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
3091

3092
_sub2ind_recurse(::Any, L, ind) = ind
14,801,889✔
3093
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,080✔
3094
    @inline
3,477✔
3095
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
11,764✔
3096
end
3097
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
2,796✔
3098
    @inline
95,341,818✔
3099
    r1 = inds[1]
95,344,913✔
3100
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
1,422,649,203✔
3101
end
3102

3103
nextL(L, l::Integer) = L*l
44,437,126✔
3104
nextL(L, r::AbstractUnitRange) = L*length(r)
696,270,632✔
3105
nextL(L, r::Slice) = L*length(r.indices)
×
3106
offsetin(i, l::Integer) = i-1
62,046,915✔
3107
offsetin(i, r::AbstractUnitRange) = i-first(r)
1,359,996,021✔
3108

3109
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
3110
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
3✔
3111
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
1,417,862✔
3112
_ind2sub(inds::Indices{1}, ind::Integer) =
3✔
3113
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3114
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
81✔
3115

3116
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3117
function _ind2sub_recurse(indslast::NTuple{1}, ind)
3118
    @inline
1,417,865✔
3119
    (_lookup(ind, indslast[1]),)
1,417,865✔
3120
end
3121
function _ind2sub_recurse(inds, ind)
3122
    @inline
2,459,375✔
3123
    r1 = inds[1]
2,459,375✔
3124
    indnext, indsub = divrem(ind, _indexlength(r1))
2,459,375✔
3125
    (_lookup(indsub, r1), _ind2sub_recurse(tail(inds), indnext)...)
2,459,375✔
3126
end
3127

3128
_indexlength(d::Integer) = d
3✔
3129
_indexlength(r::AbstractUnitRange) = length(r)
2,459,372✔
3130
_lookup(ind, d::Integer) = ind+1
6✔
3131
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
3,877,234✔
3132

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

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

3161
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3162
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3163
_sub2ind_vec(i) = ()
×
3164

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

3176
## iteration utilities ##
3177

3178
"""
3179
    foreach(f, c...) -> nothing
3180

3181
Call function `f` on each element of iterable `c`.
3182
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3183
any iterator is finished.
3184

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

3188
# Examples
3189
```jldoctest
3190
julia> tri = 1:3:7; res = Int[];
3191

3192
julia> foreach(x -> push!(res, x^2), tri)
3193

3194
julia> res
3195
3-element Vector{$(Int)}:
3196
  1
3197
 16
3198
 49
3199

3200
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3201
1 with a
3202
4 with b
3203
7 with c
3204
```
3205
"""
3206
foreach(f, itr) = (for x in itr; f(x); end; nothing)
1,188,506✔
3207
foreach(f, itr, itrs...) = (for z in zip(itr, itrs...); f(z...); end; nothing)
3✔
3208

3209
## map over arrays ##
3210

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

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

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

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

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

3234
[:, :, 2] =
3235
 11  13  15  17  19
3236
 12  14  16  18  20
3237

3238
[:, :, 3] =
3239
 21  23  25  27  29
3240
 22  24  26  28  30
3241

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

3244
julia> B = mapslices(f, A, dims=(1,2))
3245
1×4×3 Array{$Int, 3}:
3246
[:, :, 1] =
3247
 1  1  1  1
3248

3249
[:, :, 2] =
3250
 11  11  11  11
3251

3252
[:, :, 3] =
3253
 21  21  21  21
3254

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

3257
julia> B == stack(f2, eachslice(A, dims=3))
3258
true
3259

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

3262
julia> mapslices(g, A, dims=[1,3])
3263
1×5×1 Array{Rational{$Int}, 3}:
3264
[:, :, 1] =
3265
 1//21  3//23  1//5  7//27  9//29
3266

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

3275
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3276
true
3277
```
3278

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

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

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

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

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

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

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

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

3345
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
1,410✔
3346
    return R
1,329✔
3347
end
3348

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

3376
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
5,553✔
3377
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
1,350✔
3378

3379
## 1 argument
3380

3381
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
6,560,602✔
3382
    for (i,j) in zip(eachindex(dest),eachindex(A))
15,245,431✔
3383
        val = f(@inbounds A[j])
19,899,598✔
3384
        @inbounds dest[i] = val
18,984,392✔
3385
    end
30,479,101✔
3386
    return dest
7,755,748✔
3387
end
3388

3389
# map on collections
3390
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
901,734✔
3391

3392
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
3,297✔
3393
mapany(f, itr) = Any[f(x) for x in itr]
80,620,801✔
3394

3395
"""
3396
    map(f, c...) -> collection
3397

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

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

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

3405
# Examples
3406
```jldoctest
3407
julia> map(x -> x * 2, [1, 2, 3])
3408
3-element Vector{Int64}:
3409
 2
3410
 4
3411
 6
3412

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

3422
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
3✔
3423
map(f, ::AbstractSet) = error("map is not defined on sets")
3✔
3424

3425
## 2 argument
3426
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
1,098✔
3427
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
2,589✔
3428
        @inbounds a, b = A[j], B[k]
1,032,192✔
3429
        val = f(a, b)
1,032,192✔
3430
        @inbounds dest[i] = val
1,032,192✔
3431
    end
2,063,109✔
3432
    return dest
1,314✔
3433
end
3434

3435
## N argument
3436

3437
@inline ith_all(i, ::Tuple{}) = ()
20,490✔
3438
function ith_all(i, as)
3439
    @_propagate_inbounds_meta
61,470✔
3440
    return (as[1][i], ith_all(i, tail(as))...)
61,470✔
3441
end
3442

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

3461
"""
3462
    map!(function, destination, collection...)
3463

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

3467
$(_DOCS_ALIASING_WARNING)
3468

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

3471
# Examples
3472
```jldoctest
3473
julia> a = zeros(3);
3474

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

3477
julia> a
3478
3-element Vector{Float64}:
3479
 2.0
3480
 4.0
3481
 6.0
3482

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

3497
"""
3498
    map!(function, array)
3499

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

3505
# Examples
3506
```jldoctest
3507
julia> a = [1 2 3; 4 5 6];
3508

3509
julia> map!(x -> x^3, a);
3510

3511
julia> a
3512
2×3 Matrix{$Int}:
3513
  1    8   27
3514
 64  125  216
3515
```
3516
"""
3517
map!(f::F, inout::AbstractArray) where F = map!(f, inout, inout)
1,472✔
3518

3519
"""
3520
    map(f, A::AbstractArray...) -> N-array
3521

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

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

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

3534
julia> map(+, [1 2; 3 4], zeros(2,1))
3535
ERROR: DimensionMismatch
3536

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

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

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

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

3583
# sizehint! does nothing by default
3584
sizehint!(a::AbstractVector, _) = a
57✔
3585

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

3594
## keepat! ##
3595

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

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

3616
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
446✔
3617
    length(m) == length(a) || throw(BoundsError(a, m))
455✔
3618
    j = firstindex(a)
443✔
3619
    for i in eachindex(a, m)
875✔
3620
        @inbounds begin
2,635✔
3621
            if m[i]
2,635✔
3622
                i == j || (a[j] = a[i])
2,727✔
3623
                j = nextind(a, j)
2,495✔
3624
            end
3625
        end
3626
    end
4,832✔
3627
    deleteat!(a, j:lastindex(a))
443✔
3628
end
3629

3630
"""
3631
    circshift!(a::AbstractVector, shift::Integer)
3632

3633
Circularly shift, or rotate, the data in vector `a` by `shift` positions.
3634

3635
# Examples
3636

3637
```jldoctest
3638
julia> circshift!([1, 2, 3, 4, 5], 2)
3639
5-element Vector{Int64}:
3640
 4
3641
 5
3642
 1
3643
 2
3644
 3
3645

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