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

JuliaLang / julia / #37940

22 Oct 2024 05:36AM UTC coverage: 85.868% (-1.8%) from 87.654%
#37940

push

local

web-flow
Remove NewPM pass exports. (#56269)

All ecosystem consumers have switched to the string-based API.

77546 of 90308 relevant lines covered (85.87%)

16057626.0 hits per line

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

88.5
/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
61,550✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
5,406✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
8,364✔
19

20
"""
21
    size(A::AbstractArray, [dim])
22

23
Return a tuple containing the dimensions of `A`. Optionally you can specify a
24
dimension to just get the length of that dimension.
25

26
Note that `size` may not be defined for arrays with non-standard indices, in which case [`axes`](@ref)
27
may be useful. See the manual chapter on [arrays with custom indices](@ref man-custom-indices).
28

29
See also: [`length`](@ref), [`ndims`](@ref), [`eachindex`](@ref), [`sizeof`](@ref).
30

31
# Examples
32
```jldoctest
33
julia> A = fill(1, (2,3,4));
34

35
julia> size(A)
36
(2, 3, 4)
37

38
julia> size(A, 2)
39
3
40
```
41
"""
42
size(t::AbstractArray{T,N}, d) where {T,N} = d::Integer <= N ? size(t)[d] : 1
1,474,949✔
43

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

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

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

51
# Examples
52

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

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

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

63
# Usage note
64

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

69
```julia
70
ix = axes(v, 1)
71
ix[2:end]          # will work for eg Vector, but may fail in general
72
ix[(begin+1):end]  # works for generalized indexes
73
```
74
"""
75
function axes(A::AbstractArray{T,N}, d) where {T,N}
293✔
76
    @inline
71,809,238✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
71,868,916✔
78
end
79

80
"""
81
    axes(A)
82

83
Return the tuple of valid indices for array `A`.
84

85
See also: [`size`](@ref), [`keys`](@ref), [`eachindex`](@ref).
86

87
# Examples
88

89
```jldoctest
90
julia> A = fill(1, (5,6,7));
91

92
julia> axes(A)
93
(Base.OneTo(5), Base.OneTo(6), Base.OneTo(7))
94
```
95
"""
96
function axes(A)
1,099✔
97
    @inline
660,841,708✔
98
    map(unchecked_oneto, size(A))
2,147,483,647✔
99
end
100

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

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

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

120

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

215
prevind(::AbstractArray, i::Integer) = Int(i)-1
143,028✔
216
nextind(::AbstractArray, i::Integer) = Int(i)+1
341,644,769✔
217

218

219
"""
220
    eltype(type)
221

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

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

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

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

244
"""
245
    elsize(type)
246

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

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

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

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

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

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

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

278
"""
279
    length(collection) -> Integer
280

281
Return the number of elements in the collection.
282

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

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

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

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

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

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

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

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

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

317
# `eachindex` is mostly an optimization of `keys`
318
eachindex(itrs...) = keys(itrs...)
4,002,287✔
319

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

323

324
@noinline function throw_eachindex_mismatch_indices(::IndexLinear, inds...)
×
325
    throw(DimensionMismatch("all inputs to eachindex must have the same indices, got $(join(inds, ", ", " and "))"))
×
326
end
327
@noinline function throw_eachindex_mismatch_indices(::IndexCartesian, inds...)
×
328
    throw(DimensionMismatch("all inputs to eachindex must have the same axes, got $(join(inds, ", ", " and "))"))
×
329
end
330

331
"""
332
    eachindex(A...)
333
    eachindex(::IndexStyle, A::AbstractArray...)
334

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

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

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

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

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

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

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

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

380
function eachindex(A::AbstractArray, B::AbstractArray)
3✔
381
    @inline
31✔
382
    eachindex(IndexStyle(A,B), A, B)
31✔
383
end
384
function eachindex(A::AbstractArray, B::AbstractArray...)
×
385
    @inline
×
386
    eachindex(IndexStyle(A,B...), A, B...)
×
387
end
388
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
12,823,872✔
389
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
2,147,483,647✔
390
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
391
    @inline
658✔
392
    indsA = eachindex(IndexLinear(), A)
658✔
393
    _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
1,316✔
394
        throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
395
    indsA
658✔
396
end
397
function _all_match_first(f::F, inds, A, B...) where F<:Function
398
    @inline
661✔
399
    (inds == f(A)) & _all_match_first(f, inds, B...)
664✔
400
end
401
_all_match_first(f::F, inds) where F<:Function = true
×
402

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

406
"""
407
    lastindex(collection) -> Integer
408
    lastindex(collection, d) -> Integer
409

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

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

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

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

422
julia> lastindex(rand(3,4,5), 2)
423
4
424
```
425
"""
426
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
2,147,483,647✔
427
lastindex(a, d) = (@inline; last(axes(a, d)))
9,583✔
428

429
"""
430
    firstindex(collection) -> Integer
431
    firstindex(collection, d) -> Integer
432

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

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

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

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

445
julia> firstindex(rand(3,4,5), 2)
446
1
447
```
448
"""
449
firstindex(a::AbstractArray) = (@inline; first(eachindex(IndexLinear(), a)))
34,254,823✔
450
firstindex(a, d) = (@inline; first(axes(a, d)))
6,078✔
451

452
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
330,982✔
453

454
"""
455
    first(coll)
456

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

460
See also: [`only`](@ref), [`firstindex`](@ref), [`last`](@ref).
461

462
# Examples
463
```jldoctest
464
julia> first(2:2:10)
465
2
466

467
julia> first([1; 2; 3; 4])
468
1
469
```
470
"""
471
function first(itr)
1,043✔
472
    x = iterate(itr)
2,131✔
473
    x === nothing && throw(ArgumentError("collection must be non-empty"))
1,062✔
474
    x[1]
1,061✔
475
end
476

477
"""
478
    first(itr, n::Integer)
479

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

483
See also: [`startswith`](@ref), [`Iterators.take`](@ref).
484

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

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

495
julia> first(1:6, 10)
496
1:6
497

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

509
"""
510
    last(coll)
511

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

516
See also [`first`](@ref), [`endswith`](@ref).
517

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

523
julia> last([1; 2; 3; 4])
524
4
525
```
526
"""
527
last(a) = a[end]
397,340,678✔
528

529
"""
530
    last(itr, n::Integer)
531

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

535
!!! compat "Julia 1.6"
536
    This method requires at least Julia 1.6.
537

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

545
julia> last(1:6, 10)
546
1:6
547

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

559
"""
560
    strides(A)
561

562
Return a tuple of the memory strides in each dimension.
563

564
See also: [`stride`](@ref).
565

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

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

576
"""
577
    stride(A, k::Integer)
578

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

581
See also: [`strides`](@ref).
582

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

587
julia> stride(A,2)
588
3
589

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

606
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
24,464,953✔
607
size_to_strides(s, d) = (s,)
24,394,996✔
608
size_to_strides(s) = ()
×
609

610
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
4✔
611
    @boundscheck checkbounds(A, I...)
37✔
612
    return true
31✔
613
end
614

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

636
## Bounds checking ##
637

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

652
"""
653
    checkbounds(Bool, A, I...)
654

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

660
See also [`checkindex`](@ref).
661

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

666
julia> checkbounds(Bool, A, 2)
667
true
668

669
julia> checkbounds(Bool, A, 3, 4)
670
false
671

672
julia> checkbounds(Bool, A, 1:3)
673
true
674

675
julia> checkbounds(Bool, A, 1:3, 2:4)
676
false
677
```
678
"""
679
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
3,929✔
680
    @inline
399,607,375✔
681
    checkbounds_indices(Bool, axes(A), I)
415,500,109✔
682
end
683

684
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index;
685
# indices that do not allow linear indexing (e.g., logical arrays, cartesian indices, etc)
686
# must add specialized methods to implement their restrictions
687
function checkbounds(::Type{Bool}, A::AbstractArray, i)
174✔
688
    @inline
739,990,716✔
689
    return checkindex(Bool, eachindex(IndexLinear(), A), i)
2,147,483,647✔
690
end
691

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

695
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
696
"""
697
function checkbounds(A::AbstractArray, I...)
4,007✔
698
    @inline
1,129,567,100✔
699
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
2,147,483,647✔
700
    nothing
701
end
702

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

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

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

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

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

721
See also [`checkbounds`](@ref).
722
"""
723
function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{Any, Vararg})
3,550✔
724
    @inline
24,800,933✔
725
    return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
972,018,914✔
726
        checkbounds_indices(Bool, safe_tail(inds), tail(I))
727
end
728

729
checkbounds_indices(::Type{Bool}, inds::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, inds))
578,190✔
730

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

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

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

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

747
julia> checkindex(Bool, 1:20, 21)
748
false
749
```
750
"""
751
checkindex(::Type{Bool}, inds, i) = throw(ArgumentError(LazyString("unable to check bounds for indices of type ", typeof(i))))
2✔
752
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
63,307,605✔
753
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
25,667✔
754
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
2,147,483,647✔
755
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
×
756
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
×
757
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::AbstractRange) =
400,586,345✔
758
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
759
# range like indices with cheap `extrema`
760
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::LinearIndices) =
145✔
761
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
762

763
function checkindex(::Type{Bool}, inds, I::AbstractArray)
764
    @inline
6,546✔
765
    b = true
6,546✔
766
    for i in I
21,711✔
767
        b &= checkindex(Bool, inds, i)
6,328,547✔
768
    end
6,334,494✔
769
    b
19,772✔
770
end
771

772
# See also specializations in multidimensional
773

774
## Constructors ##
775

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

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

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

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

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

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

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

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

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

818
See also: [`undef`](@ref), [`isassigned`](@ref).
819
"""
820
similar(a::AbstractArray{T}) where {T}                             = similar(a, T)
14,532✔
821
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
11,388✔
822
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
104,697,321✔
823
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
2,976✔
824
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
9,438,964✔
825
# Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
826
# thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
827
# but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
828
# define this method to convert supported axes to Ints, with the expectation that an offset array
829
# package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
830
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
316,443✔
831
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims))
5✔
832
# similar creates an Array by default
833
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N}    = Array{T,N}(undef, dims)
9,379,017✔
834

835
to_shape(::Tuple{}) = ()
33✔
836
to_shape(dims::Dims) = dims
5,480✔
837
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
12,432,631✔
838
# each dimension
839
to_shape(i::Int) = i
111✔
840
to_shape(i::Integer) = Int(i)
182✔
841
to_shape(r::OneTo) = Int(last(r))
8,137,817✔
842
to_shape(r::AbstractUnitRange) = r
1,522✔
843

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

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

851
**Examples**:
852

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

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

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

863
would create a 1-dimensional logical array whose indices match those
864
of the columns of `A`.
865
"""
866
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
4✔
867
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
1,089,438,306✔
868
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
1,089,442,572✔
869

870
"""
871
    empty(v::AbstractVector, [eltype])
872

873
Create an empty vector similar to `v`, optionally changing the `eltype`.
874

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

877
# Examples
878

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

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

889
# like empty, but should return a mutable collection, a Vector by default
890
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
99✔
891
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
49✔
892

893
"""
894
    copy!(dst, src) -> dst
895

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

903
$(_DOCS_ALIASING_WARNING)
904

905
See also [`copyto!`](@ref).
906

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

911
!!! compat "Julia 1.1"
912
    This method requires at least Julia 1.1. In Julia 1.0 this method
913
    is available from the `Future` standard library as `Future.copy!`.
914
"""
915
function copy!(dst::AbstractVector, src::AbstractVector)
23,199,530✔
916
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
72✔
917
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
918
    if length(dst) != length(src)
23,199,597✔
919
        resize!(dst, length(src))
22,980,748✔
920
    end
921
    copyto!(dst, src)
23,199,666✔
922
end
923

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

930
## from general iterable to any array
931

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

936
function copyto!(dest::AbstractArray, src)
4,603,521✔
937
    destiter = eachindex(dest)
4,617,909✔
938
    y = iterate(destiter)
4,617,919✔
939
    for x in src
8,466,460✔
940
        y === nothing &&
5,554,122✔
941
            throw(ArgumentError("destination has fewer elements than required"))
942
        dest[y[1]] = x
5,554,121✔
943
        y = iterate(destiter, y[2])
9,207,756✔
944
    end
9,255,292✔
945
    return dest
4,617,907✔
946
end
947

948
function copyto!(dest::AbstractArray, dstart::Integer, src)
254✔
949
    i = Int(dstart)
277✔
950
    if haslength(src) && length(dest) > 0
277✔
951
        @boundscheck checkbounds(dest, i:(i + length(src) - 1))
273✔
952
        for x in src
286✔
953
            @inbounds dest[i] = x
2,350✔
954
            i += 1
2,350✔
955
        end
2,829✔
956
    else
957
        for x in src
5✔
958
            dest[i] = x
9✔
959
            i += 1
3✔
960
        end
3✔
961
    end
962
    return dest
273✔
963
end
964

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

994
# this method must be separate from the above since src might not have a length
995
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
635,701✔
996
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
635,701✔
997
        ", elements, but n should be non-negative")))
998
    n == 0 && return dest
635,700✔
999
    dmax = dstart + n - 1
635,699✔
1000
    inds = LinearIndices(dest)
635,699✔
1001
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
1,271,396✔
1002
        sstart < 1 && throw(ArgumentError(LazyString("source start offset (",
4✔
1003
            sstart,") is < 1")))
1004
        throw(BoundsError(dest, dstart:dmax))
3✔
1005
    end
1006
    y = iterate(src)
635,695✔
1007
    for j = 1:(sstart-1)
689,118✔
1008
        if y === nothing
2,147,483,647✔
1009
            throw(ArgumentError(LazyString(
1✔
1010
                "source has fewer elements than required, ",
1011
                "expected at least ",sstart,", got ",j-1)))
1012
        end
1013
        y = iterate(src, y[2])
2,147,483,647✔
1014
    end
2,147,483,647✔
1015
    i = Int(dstart)
635,694✔
1016
    while i <= dmax && y !== nothing
11,244,834✔
1017
        val, st = y
9,020,537✔
1018
        @inbounds dest[i] = val
10,609,140✔
1019
        y = iterate(src, st)
11,144,536✔
1020
        i += 1
10,609,140✔
1021
    end
10,609,140✔
1022
    i <= dmax && throw(BoundsError(dest, i))
635,694✔
1023
    return dest
635,693✔
1024
end
1025

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

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

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

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

1038
$(_DOCS_ALIASING_WARNING)
1039

1040
# Examples
1041
```jldoctest
1042
julia> x = [1., 0., 3., 0., 5.];
1043

1044
julia> y = zeros(7);
1045

1046
julia> copyto!(y, x);
1047

1048
julia> y
1049
7-element Vector{Float64}:
1050
 1.0
1051
 0.0
1052
 3.0
1053
 0.0
1054
 5.0
1055
 0.0
1056
 0.0
1057
```
1058
"""
1059
function copyto!(dest::AbstractArray, src::AbstractArray)
2,753,610✔
1060
    isempty(src) && return dest
2,995,350✔
1061
    if dest isa BitArray
2,787,550✔
1062
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1063
        return _copyto_bitarray!(dest, src)
1✔
1064
    end
1065
    src′ = unalias(dest, src)
2,991,207✔
1066
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,995,170✔
1067
end
1068

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

1075
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
66,622✔
1076
    isempty(src) && return dest
2,988,853✔
1077
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,988,854✔
1078
    idf, isf = first(destinds), first(srcinds)
2,781,326✔
1079
    Δi = idf - isf
2,781,326✔
1080
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,988,860✔
1081
        throw(BoundsError(dest, srcinds))
1082
    if deststyle isa IndexLinear
2,781,319✔
1083
        if srcstyle isa IndexLinear
2,778,170✔
1084
            # Single-index implementation
1085
            @inbounds for i in srcinds
2,782,798✔
1086
                dest[i + Δi] = src[i]
51,516,962✔
1087
            end
100,251,129✔
1088
        else
1089
            # Dual-index implementation
1090
            i = idf - 1
19,855✔
1091
            @inbounds for a in src
405,780✔
1092
                dest[i+=1] = a
2,476,550✔
1093
            end
4,750,032✔
1094
        end
1095
    else
1096
        iterdest, itersrc = eachindex(dest), eachindex(src)
3,149✔
1097
        if iterdest == itersrc
3,150✔
1098
            # Shared-iterator implementation
1099
            for I in iterdest
308✔
1100
                @inbounds dest[I] = src[I]
6,011,660✔
1101
            end
12,012,712✔
1102
        else
1103
            # Dual-iterator implementation
1104
            for (Idest, Isrc) in zip(iterdest, itersrc)
5,942✔
1105
                @inbounds dest[Idest] = src[Isrc]
2,033,822✔
1106
            end
4,064,633✔
1107
        end
1108
    end
1109
    return dest
2,988,838✔
1110
end
1111

1112
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
71✔
1113
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
198,059✔
1114
end
1115

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

1122
function copyto!(dest::AbstractArray, dstart::Integer,
930,552✔
1123
                 src::AbstractArray, sstart::Integer,
1124
                 n::Integer)
1125
    n == 0 && return dest
930,552✔
1126
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
930,550✔
1127
        n," elements, but n should be non-negative")))
1128
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
930,549✔
1129
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
930,561✔
1130
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
930,540✔
1131
    src′ = unalias(dest, src)
930,534✔
1132
    @inbounds for i = 0:n-1
930,611✔
1133
        dest[dstart+i] = src′[sstart+i]
47,911,351✔
1134
    end
94,892,168✔
1135
    return dest
930,534✔
1136
end
1137

1138
function copy(a::AbstractArray)
142,411✔
1139
    @_propagate_inbounds_meta
146,774✔
1140
    copymutable(a)
152,903✔
1141
end
1142

1143
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
756✔
1144
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1145
    if length(ir_dest) != length(ir_src)
756✔
1146
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1147
            length(ir_src)," and ",length(ir_dest),")")))
1148
    end
1149
    if length(jr_dest) != length(jr_src)
756✔
1150
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1151
            length(jr_src)," and ",length(jr_dest),")")))
1152
    end
1153
    @boundscheck checkbounds(B, ir_dest, jr_dest)
756✔
1154
    @boundscheck checkbounds(A, ir_src, jr_src)
756✔
1155
    A′ = unalias(B, A)
756✔
1156
    jdest = first(jr_dest)
756✔
1157
    for jsrc in jr_src
1,511✔
1158
        idest = first(ir_dest)
11,508✔
1159
        for isrc in ir_src
23,013✔
1160
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
179,256✔
1161
            idest += step(ir_dest)
179,256✔
1162
        end
347,004✔
1163
        jdest += step(jr_dest)
11,508✔
1164
    end
22,260✔
1165
    return B
756✔
1166
end
1167

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

1170
function copyto_axcheck!(dest, src)
191,306✔
1171
    _checkaxs(axes(dest), axes(src))
228,628✔
1172
    copyto!(dest, src)
242,510✔
1173
end
1174

1175
"""
1176
    copymutable(a)
1177

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

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

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

1201
zero(x::AbstractArray{T}) where {T<:Number} = fill!(similar(x, typeof(zero(T))), zero(T))
4,325✔
1202
zero(x::AbstractArray{S}) where {S<:Union{Missing, Number}} = fill!(similar(x, typeof(zero(S))), zero(S))
3✔
1203
zero(x::AbstractArray) = map(zero, x)
2✔
1204

1205
function _one(unit::T, mat::AbstractMatrix) where {T}
161✔
1206
    (rows, cols) = axes(mat)
161✔
1207
    (length(rows) == length(cols)) ||
161✔
1208
      throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
1209
    zer = zero(unit)::T
161✔
1210
    require_one_based_indexing(mat)
161✔
1211
    I = similar(mat, T)
321✔
1212
    fill!(I, zer)
3,783✔
1213
    for i ∈ rows
161✔
1214
        I[i, i] = unit
656✔
1215
    end
1,151✔
1216
    I
161✔
1217
end
1218

1219
one(x::AbstractMatrix{T}) where {T} = _one(one(T), x)
137✔
1220
oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
30✔
1221

1222
## iteration support for arrays by iterating over `eachindex` in the array ##
1223
# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1224

1225
# While the definitions for IndexLinear are all simple enough to inline on their
1226
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1227
# inlining.
1228
function iterate(A::AbstractArray, state=(eachindex(A),))
2,254✔
1229
    y = iterate(state...)
165,404,900✔
1230
    y === nothing && return nothing
132,687,831✔
1231
    A[y[1]], (state[1], tail(y)...)
132,096,430✔
1232
end
1233

1234
isempty(a::AbstractArray) = (length(a) == 0)
2,147,483,647✔
1235

1236

1237
## range conversions ##
1238

1239
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
2✔
1240
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
165✔
1241
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
6✔
1242
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
1243
    LinRange(T(r.start), T(r.stop), length(r))
1✔
1244
end
1245

1246
## unsafe/pointer conversions ##
1247

1248
# note: the following type definitions don't mean any AbstractArray is convertible to
1249
# a data Ref. they just map the array element type to the pointer type for
1250
# convenience in cases that work.
1251
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
78,404,550✔
1252
function pointer(x::AbstractArray{T}, i::Integer) where T
101,871✔
1253
    @inline
437,445✔
1254
    pointer(x) + Int(_memory_offset(x, i))::Int
4,883,174✔
1255
end
1256

1257
# The distance from pointer(x) to the element at x[I...] in bytes
1258
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
4,510,274✔
1259
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
48,708✔
1260
    J = _to_subscript_indices(x, I...)
102,054✔
1261
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
383,661✔
1262
end
1263

1264
## Special constprop heuristics for getindex/setindex
1265
typename(typeof(function getindex end)).constprop_heuristic = Core.ARRAY_INDEX_HEURISTIC
1266
typename(typeof(function setindex! end)).constprop_heuristic = Core.ARRAY_INDEX_HEURISTIC
1267

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

1280
Return a subset of array `A` as selected by the indices `inds`.
1281

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

1286
When `inds` selects multiple elements, this function returns a newly
1287
allocated array. To index multiple elements without making a copy,
1288
use [`view`](@ref) instead.
1289

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

1292
# Examples
1293
```jldoctest
1294
julia> A = [1 2; 3 4]
1295
2×2 Matrix{Int64}:
1296
 1  2
1297
 3  4
1298

1299
julia> getindex(A, 1)
1300
1
1301

1302
julia> getindex(A, [2, 1])
1303
2-element Vector{Int64}:
1304
 3
1305
 1
1306

1307
julia> getindex(A, 2:4)
1308
3-element Vector{Int64}:
1309
 3
1310
 2
1311
 4
1312

1313
julia> getindex(A, 2, 1)
1314
3
1315

1316
julia> getindex(A, CartesianIndex(2, 1))
1317
3
1318

1319
julia> getindex(A, :, 2)
1320
2-element Vector{Int64}:
1321
 2
1322
 4
1323

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

1329
julia> getindex(A, A .> 2)
1330
2-element Vector{Int64}:
1331
 3
1332
 4
1333
```
1334
"""
1335
function getindex(A::AbstractArray, I...)
529,271✔
1336
    @_propagate_inbounds_meta
111,388,614✔
1337
    error_if_canonical_getindex(IndexStyle(A), A, I...)
111,388,614✔
1338
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
215,931,425✔
1339
end
1340
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1341
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
176,064,554✔
1342

1343
@inline unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
389✔
1344

1345
struct CanonicalIndexError <: Exception
1346
    func::String
1347
    type::Any
1348
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
19✔
1349
end
1350

1351
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1352
    throw(CanonicalIndexError("getindex", typeof(A)))
1353
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1354
    throw(CanonicalIndexError("getindex", typeof(A)))
1355
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
×
1356

1357
## Internal definitions
1358
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1359
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1360

1361
## IndexLinear Scalar indexing: canonical method is one Int
1362
_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)
47,771,607✔
1363
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
51✔
1364
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
342✔
1365
    @inline
2,395,668✔
1366
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
35,783,991✔
1367
    @inbounds r = getindex(A, _to_linear_index(A, I...))
35,783,925✔
1368
    r
2,395,617✔
1369
end
1370
_to_linear_index(A::AbstractArray, i::Integer) = i
52,131✔
1371
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
85,177,742✔
1372
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
329,319✔
1373
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
283,763,571✔
1374

1375
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1376
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
1377
    @inline
427,237✔
1378
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
427,309✔
1379
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
430,365✔
1380
    r
427,163✔
1381
end
1382
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
1383
    @_propagate_inbounds_meta
107,043,816✔
1384
    getindex(A, I...)
131,420,429✔
1385
end
1386
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
443,625✔
1387
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1388
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1389
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
416✔
1390
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1391
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1392
    @inline
97,832✔
1393
    J, Jrem = IteratorsMD.split(I, Val(N))
97,832✔
1394
    _to_subscript_indices(A, J, Jrem)
97,832✔
1395
end
1396
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1397
    __to_subscript_indices(A, axes(A), J, Jrem)
1398
function __to_subscript_indices(A::AbstractArray,
1399
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1400
    @inline
2✔
1401
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1402
end
1403
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
97,830✔
1404
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
30,862✔
1405
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1406
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1407
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1408
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
443,625✔
1409

1410
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1411
# function that allows dispatch on array storage
1412

1413
"""
1414
    setindex!(A, X, inds...)
1415
    A[inds...] = X
1416

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

1420
$(_DOCS_ALIASING_WARNING)
1421

1422
# Examples
1423
```jldoctest
1424
julia> A = zeros(2,2);
1425

1426
julia> setindex!(A, [10, 20], [1, 2]);
1427

1428
julia> A[[3, 4]] = [30, 40];
1429

1430
julia> A
1431
2×2 Matrix{Float64}:
1432
 10.0  30.0
1433
 20.0  40.0
1434
```
1435
"""
1436
function setindex!(A::AbstractArray, v, I...)
1,037✔
1437
    @_propagate_inbounds_meta
3,061,570✔
1438
    error_if_canonical_setindex(IndexStyle(A), A, I...)
3,061,570✔
1439
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
9,486,262✔
1440
end
1441
function unsafe_setindex!(A::AbstractArray, v, I...)
1442
    @inline
732✔
1443
    @inbounds r = setindex!(A, v, I...)
732✔
1444
    r
730✔
1445
end
1446

1447
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
12✔
1448
    throw(CanonicalIndexError("setindex!", typeof(A)))
1449
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1450
    throw(CanonicalIndexError("setindex!", typeof(A)))
1451
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
×
1452

1453
## Internal definitions
1454
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1455
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1456

1457
## IndexLinear Scalar indexing
1458
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
6,502,276✔
1459
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
696✔
1460
    @inline
200,012✔
1461
    @boundscheck checkbounds(A, I...)
305,977✔
1462
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
305,940✔
1463
    r
199,991✔
1464
end
1465

1466
# IndexCartesian Scalar indexing
1467
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
1468
    @_propagate_inbounds_meta
2,398,245✔
1469
    setindex!(A, v, I...)
2,398,258✔
1470
end
1471
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
1472
    @inline
40,734✔
1473
    @boundscheck checkbounds(A, I...)
40,739✔
1474
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
40,729✔
1475
    r
40,729✔
1476
end
1477

1478
_unsetindex!(A::AbstractArray, i::Integer) = _unsetindex!(A, to_index(i))
×
1479

1480
"""
1481
    parent(A)
1482

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

1488
# Examples
1489
```jldoctest
1490
julia> A = [1 2; 3 4]
1491
2×2 Matrix{Int64}:
1492
 1  2
1493
 3  4
1494

1495
julia> V = view(A, 1:2, :)
1496
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1497
 1  2
1498
 3  4
1499

1500
julia> parent(V)
1501
2×2 Matrix{Int64}:
1502
 1  2
1503
 3  4
1504
```
1505
"""
1506
function parent end
1507

1508
parent(a::AbstractArray) = a
1,686✔
1509

1510
## rudimentary aliasing detection ##
1511
"""
1512
    Base.unalias(dest, A)
1513

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

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

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

1524
See also [`Base.mightalias`](@ref).
1525
"""
1526
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
6,725,603✔
1527
unalias(dest, A::AbstractRange) = A
32,956,514✔
1528
unalias(dest, A) = A
3,218,295✔
1529

1530
"""
1531
    Base.unaliascopy(A)
1532

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

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

1555
"""
1556
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1557

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

1560
By default, this simply checks if either of the arrays reference the same memory
1561
regions, as identified by their [`Base.dataids`](@ref).
1562
"""
1563
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B))
6,729,307✔
1564
mightalias(x, y) = false
×
1565

1566
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1567
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1568
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1569
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1570
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
6,593,882✔
1571
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
46,334✔
1572
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1573
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
3,206✔
1574
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
64,459✔
1575

1576
"""
1577
    Base.dataids(A::AbstractArray)
1578

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

1581
Custom arrays that would like to opt-in to aliasing detection of their component
1582
parts can specialize this method to return the concatenation of the `dataids` of
1583
their component parts.  A typical definition for an array that wraps a parent is
1584
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1585
"""
1586
dataids(A::AbstractArray) = (UInt(objectid(A)),)
494,459✔
1587
dataids(A::Memory) = (B = ccall(:jl_genericmemory_owner, Any, (Any,), A); (UInt(pointer(B isa typeof(A) ? B : A)),))
12,808,694✔
1588
dataids(A::Array) = dataids(A.ref.mem)
9,136,111✔
1589
dataids(::AbstractRange) = ()
2,833,083✔
1590
dataids(x) = ()
16,250✔
1591

1592
## get (getindex with a default value) ##
1593

1594
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1595
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1596

1597
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
334✔
1598
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
8✔
1599
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
13✔
1600
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
4✔
1601
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
7✔
1602
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
9✔
1603

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

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

1624
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
×
1625
    fill!(X, default)
×
1626
    dst, src = indcopy(size(A), I)
×
1627
    X[dst...] = A[src...]
×
1628
    X
×
1629
end
1630

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

1634
## structured matrix methods ##
1635
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
23,933✔
1636
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
32,563✔
1637

1638
## Concatenation ##
1639
eltypeof(x) = typeof(x)
14,632✔
1640
eltypeof(x::AbstractArray) = eltype(x)
14,533✔
1641

1642
promote_eltypeof() = error()
×
1643
promote_eltypeof(v1) = eltypeof(v1)
×
1644
promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2))
1,340✔
1645
promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...))
26,570✔
1646
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
6,852✔
1647
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
20✔
1648

1649
promote_eltype() = error()
×
1650
promote_eltype(v1) = eltype(v1)
×
1651
promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2))
1,678✔
1652
promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...))
485✔
1653
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
28✔
1654
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
1,405✔
1655

1656
#TODO: ERROR CHECK
1657
_cat(catdim::Int) = Vector{Any}()
1✔
1658

1659
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1660
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1661

1662
## cat: special cases
1663
vcat(X::T...) where {T}         = T[ X[i] for i=eachindex(X) ]
327✔
1664
vcat(X::T...) where {T<:Number} = T[ X[i] for i=eachindex(X) ]
226✔
1665
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=eachindex(X) ]
95✔
1666
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=eachindex(X) ]
8,000,506✔
1667

1668
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
1✔
1669
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
1✔
1670
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
9✔
1671
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
51✔
1672

1673
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
3✔
1674
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
5✔
1675

1676
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1677
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1678
# but that solution currently fails (see #27188 and #27224)
1679
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1680

1681
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
1,497,726✔
1682
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
1,543,644✔
1683
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1684

1685
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
790,564✔
1686
    pos = 1
795,377✔
1687
    for k=1:Int(length(V))::Int
795,379✔
1688
        Vk = V[k]
795,698✔
1689
        p1 = pos + Int(length(Vk))::Int - 1
795,725✔
1690
        a[pos:p1] = Vk
5,789,559✔
1691
        pos = p1+1
795,698✔
1692
    end
795,939✔
1693
    a
795,377✔
1694
end
1695

1696
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
1,031✔
1697

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

1705

1706
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
299✔
1707
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
267✔
1708

1709
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1,035✔
1710
    nargs = length(A)
1,037✔
1711
    nrows = size(A[1], 1)
1,037✔
1712
    ncols = 0
1,037✔
1713
    dense = true
1,037✔
1714
    for j = 1:nargs
1,037✔
1715
        Aj = A[j]
2,137✔
1716
        if size(Aj, 1) != nrows
2,925✔
1717
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1718
        end
1719
        dense &= isa(Aj,Array)
2,136✔
1720
        nd = ndims(Aj)
2,923✔
1721
        ncols += (nd==2 ? size(Aj,2) : 1)
2,616✔
1722
    end
3,236✔
1723
    B = similar(A[1], T, nrows, ncols)
1,618✔
1724
    pos = 1
1,036✔
1725
    if dense
1,036✔
1726
        for k=1:nargs
402✔
1727
            Ak = A[k]
828✔
1728
            n = length(Ak)
1,050✔
1729
            copyto!(B, pos, Ak, 1, n)
1,402✔
1730
            pos += n
828✔
1731
        end
1,254✔
1732
    else
1733
        for k=1:nargs
634✔
1734
            Ak = A[k]
1,307✔
1735
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
1,580✔
1736
            B[:, pos:p1] = Ak
1,709✔
1737
            pos = p1+1
1,307✔
1738
        end
1,844✔
1739
    end
1740
    return B
1,036✔
1741
end
1742

1743
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
67✔
1744
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
198✔
1745

1746
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
467✔
1747
    nargs = length(A)
479✔
1748
    nrows = sum(a->size(a, 1), A)::Int
1,562✔
1749
    ncols = size(A[1], 2)
479✔
1750
    for j = 2:nargs
479✔
1751
        if size(A[j], 2) != ncols
575✔
1752
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1753
        end
1754
    end
642✔
1755
    B = similar(A[1], T, nrows, ncols)
855✔
1756
    pos = 1
478✔
1757
    for k=1:nargs
478✔
1758
        Ak = A[k]
1,032✔
1759
        p1 = pos+size(Ak,1)::Int-1
1,215✔
1760
        B[pos:p1, :] = Ak
1,088✔
1761
        pos = p1+1
1,032✔
1762
    end
1,586✔
1763
    return B
478✔
1764
end
1765

1766
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
1,544,115✔
1767

1768
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
8✔
1769
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1770

1771
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1772
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1773

1774
## cat: general case
1775

1776
# helper functions
1777
cat_size(A) = (1,)
22,536✔
1778
cat_size(A::AbstractArray) = size(A)
16,215✔
1779
cat_size(A, d) = 1
×
1780
cat_size(A::AbstractArray, d) = size(A, d)
29,633✔
1781

1782
cat_length(::Any) = 1
×
1783
cat_length(a::AbstractArray) = length(a)
472✔
1784

1785
cat_ndims(a) = 0
×
1786
cat_ndims(a::AbstractArray) = ndims(a)
685✔
1787

1788
cat_indices(A, d) = OneTo(1)
22,532✔
1789
cat_indices(A::AbstractArray, d) = axes(A, d)
17,729✔
1790

1791
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,563✔
1792
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1793
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,621✔
1794
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1795
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
850✔
1796
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1797

1798
# These are for backwards compatibility (even though internal)
1799
cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
×
1800
function cat_shape(dims, shapes::Tuple)
4✔
1801
    out_shape = ()
4✔
1802
    for s in shapes
4✔
1803
        out_shape = _cshp(1, dims, out_shape, s)
18✔
1804
    end
15✔
1805
    return out_shape
4✔
1806
end
1807
# The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1808
cat_size_shape(dims) = ntuple(zero, Val(length(dims)))
×
1809
@inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
9,297✔
1810
_cat_size_shape(dims, shape) = shape
1,410✔
1811
@inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
29,655✔
1812

1813
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1814
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1815
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
472✔
1816
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
469✔
1817
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1818
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
2,243✔
1819
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1820
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
1821
    _cs(ndim, shape[1], 1)
23✔
1822
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
19✔
1823
end
1824
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
1825
    next = _cs(ndim, shape[1], nshape[1])
154✔
1826
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
154✔
1827
end
1828
@inline function _cshp(ndim::Int, dims, shape, nshape)
86✔
1829
    a = shape[1]
30,436✔
1830
    b = nshape[1]
30,436✔
1831
    next = dims[1] ? a + b : _cs(ndim, a, b)
30,920✔
1832
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
30,510✔
1833
end
1834

1835
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,021✔
1836
    "mismatch in dimension $d (expected $a got $b)")))
1837

1838
dims2cat(::Val{dims}) where dims = dims2cat(dims)
502✔
1839
function dims2cat(dims)
3✔
1840
    if any(≤(0), dims)
2,876✔
1841
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1842
    end
1843
    ntuple(in(dims), maximum(dims))
2,100✔
1844
end
1845

1846
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
8,210✔
1847

1848
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
7,894✔
1849
    catdims = dims2cat(dims)
9,924✔
1850
    shape = cat_size_shape(catdims, X...)
9,297✔
1851
    A = cat_similar(X[1], T, shape)
9,992✔
1852
    if count(!iszero, catdims)::Int > 1
9,121✔
1853
        fill!(A, zero(T))
785✔
1854
    end
1855
    return __cat(A, shape, catdims, X...)
9,226✔
1856
end
1857
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1858
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1859
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1860

1861
# Why isn't this called `__cat!`?
1862
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
9,738✔
1863

1864
function __cat_offset!(A, shape, catdims, offsets, x, X...)
35,938✔
1865
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1866
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
83,950✔
1867
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
38,865✔
1868
end
1869
__cat_offset!(A, shape, catdims, offsets) = A
9,124✔
1870

1871
function __cat_offset1!(A, shape, catdims, offsets, x)
2✔
1872
    inds = ntuple(length(offsets)) do i
38,999✔
1873
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
42,328✔
1874
    end
1875
    _copy_or_fill!(A, inds, x)
129,103✔
1876
    newoffsets = ntuple(length(offsets)) do i
38,830✔
1877
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
41,107✔
1878
    end
1879
    return newoffsets
38,828✔
1880
end
1881

1882
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
23,406✔
1883
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
105,661✔
1884

1885
"""
1886
    vcat(A...)
1887

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

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

1894
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1895

1896
# Examples
1897
```jldoctest
1898
julia> v = vcat([1,2], [3,4])
1899
4-element Vector{Int64}:
1900
 1
1901
 2
1902
 3
1903
 4
1904

1905
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1906
true
1907

1908
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1909
true
1910

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

1914
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1915
3-element Vector{Float64}:
1916
 1.0
1917
 1.5
1918
 2.0
1919

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

1923
julia> vcat(two...)
1924
3×3 Matrix{Float64}:
1925
 10.0  20.0  30.0
1926
  4.0   5.0   6.0
1927
  7.0   8.0   9.0
1928

1929
julia> vs = [[1, 2], [3, 4], [5, 6]];
1930

1931
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1932
6-element Vector{Int64}:
1933
 1
1934
 2
1935
 3
1936
 4
1937
 5
1938
 6
1939

1940
julia> ans == collect(Iterators.flatten(vs))
1941
true
1942
```
1943
"""
1944
vcat(X...) = cat(X...; dims=Val(1))
437✔
1945
"""
1946
    hcat(A...)
1947

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

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

1955
See also [`vcat`](@ref), [`hvcat`](@ref).
1956

1957
# Examples
1958
```jldoctest
1959
julia> hcat([1,2], [3,4], [5,6])
1960
2×3 Matrix{Int64}:
1961
 1  3  5
1962
 2  4  6
1963

1964
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1965
1×7 Matrix{Int64}:
1966
 1  2  30  40  5  6  7
1967

1968
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1969
true
1970

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

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

1977
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
1978
2×6 Matrix{Float64}:
1979
 0.0  0.0  1.0  2.0  50.0  60.0
1980
 0.0  0.0  3.0  4.0  70.0  80.0
1981

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

1985
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
1986
0×3 Matrix{Int64}
1987

1988
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
1989
2×1 Matrix{Any}:
1990
 1.1
1991
 9.9
1992
```
1993
"""
1994
hcat(X...) = cat(X...; dims=Val(2))
8✔
1995

1996
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
394✔
1997
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
298✔
1998

1999
"""
2000
    cat(A...; dims)
2001

2002
Concatenate the input arrays along the dimensions specified in `dims`.
2003

2004
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
2005
a in A)`.
2006
Along other dimensions, all input arrays should have the same size,
2007
which will also be the size of the output array along those dimensions.
2008

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

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

2018
The keyword also accepts `Val(dims)`.
2019

2020
!!! compat "Julia 1.8"
2021
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
2022

2023
# Examples
2024

2025
Concatenate two arrays in different dimensions:
2026
```jldoctest
2027
julia> a = [1 2 3]
2028
1×3 Matrix{Int64}:
2029
 1  2  3
2030

2031
julia> b = [4 5 6]
2032
1×3 Matrix{Int64}:
2033
 4  5  6
2034

2035
julia> cat(a, b; dims=1)
2036
2×3 Matrix{Int64}:
2037
 1  2  3
2038
 4  5  6
2039

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

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

2050
# Extended Help
2051

2052
Concatenate 3D arrays:
2053
```jldoctest
2054
julia> a = ones(2, 2, 3);
2055

2056
julia> b = ones(2, 2, 4);
2057

2058
julia> c = cat(a, b; dims=3);
2059

2060
julia> size(c) == (2, 2, 7)
2061
true
2062
```
2063

2064
Concatenate arrays of different sizes:
2065
```jldoctest
2066
julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2)  # same as hcat
2067
2×6×1 Array{Float64, 3}:
2068
[:, :, 1] =
2069
 1.0  2.0  3.14159  10.0  10.0  10.0
2070
 3.0  4.0  3.14159  10.0  10.0  10.0
2071
```
2072

2073
Construct a block diagonal matrix:
2074
```
2075
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
2076
4×7 Matrix{Bool}:
2077
 1  0  0  0  0  0  0
2078
 0  1  1  0  0  0  0
2079
 0  1  1  0  0  0  0
2080
 0  0  0  1  1  1  1
2081
```
2082

2083
```
2084
julia> cat(1, [2], [3;;]; dims=Val(2))
2085
1×3 Matrix{Int64}:
2086
 1  2  3
2087
```
2088

2089
!!! note
2090
    `cat` does not join two strings, you may want to use `*`.
2091

2092
```jldoctest
2093
julia> a = "aaa";
2094

2095
julia> b = "bbb";
2096

2097
julia> cat(a, b; dims=1)
2098
2-element Vector{String}:
2099
 "aaa"
2100
 "bbb"
2101

2102
julia> cat(a, b; dims=2)
2103
1×2 Matrix{String}:
2104
 "aaa"  "bbb"
2105

2106
julia> a * b
2107
"aaabbb"
2108
```
2109
"""
2110
@inline cat(A...; dims) = _cat(dims, A...)
17,261✔
2111
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
2112
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
201✔
2113

2114
# The specializations for 1 and 2 inputs are important
2115
# especially when running with --inline=no, see #11158
2116
vcat(A::AbstractArray) = cat(A; dims=Val(1))
1✔
2117
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
2✔
2118
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
2119
vcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(1))
7,063✔
2120
hcat(A::AbstractArray) = cat(A; dims=Val(2))
1✔
2121
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
1✔
2122
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
1✔
2123
hcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(2))
7✔
2124

2125
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
2126
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2127
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
2128
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2129
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
2130
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
2131

2132
# 2d horizontal and vertical concatenation
2133

2134
# these are produced in lowering if splatting occurs inside hvcat
2135
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
3✔
2136
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
3✔
2137

2138
function hvcat(nbc::Int, as...)
10✔
2139
    # nbc = # of block columns
2140
    n = length(as)
10✔
2141
    mod(n,nbc) != 0 &&
20✔
2142
        throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
2143
    nbr = div(n,nbc)
9✔
2144
    hvcat(ntuple(Returns(nbc), nbr), as...)
9✔
2145
end
2146

2147
"""
2148
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2149

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

2155
# Examples
2156
```jldoctest
2157
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2158
(1, 2, 3, 4, 5, 6)
2159

2160
julia> [a b c; d e f]
2161
2×3 Matrix{Int64}:
2162
 1  2  3
2163
 4  5  6
2164

2165
julia> hvcat((3,3), a,b,c,d,e,f)
2166
2×3 Matrix{Int64}:
2167
 1  2  3
2168
 4  5  6
2169

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

2176
julia> hvcat((2,2,2), a,b,c,d,e,f)
2177
3×2 Matrix{Int64}:
2178
 1  2
2179
 3  4
2180
 5  6
2181
julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f)
2182
true
2183
```
2184
"""
2185
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
323✔
2186
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray{T}...) where {T} = typed_hvcat(T, rows, xs...)
513✔
2187

2188
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T
876✔
2189
    nbr = length(rows)  # number of block rows
876✔
2190

2191
    nc = 0
876✔
2192
    for i=1:rows[1]
876✔
2193
        nc += size(as[i],2)
1,685✔
2194
    end
2,494✔
2195

2196
    nr = 0
876✔
2197
    a = 1
876✔
2198
    for i = 1:nbr
876✔
2199
        nr += size(as[a],1)
1,419✔
2200
        a += rows[i]
1,419✔
2201
    end
1,962✔
2202

2203
    out = similar(as[1], T, nr, nc)
914✔
2204

2205
    a = 1
876✔
2206
    r = 1
876✔
2207
    for i = 1:nbr
876✔
2208
        c = 1
1,419✔
2209
        szi = size(as[a],1)
1,419✔
2210
        for j = 1:rows[i]
1,419✔
2211
            Aj = as[a+j-1]
2,615✔
2212
            szj = size(Aj,2)
2,615✔
2213
            if size(Aj,1) != szi
2,615✔
2214
                throw(DimensionMismatch("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
1✔
2215
            end
2216
            if c-1+szj > nc
3,907✔
2217
                throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
1✔
2218
            end
2219
            out[r:r-1+szi, c:c-1+szj] = Aj
3,829✔
2220
            c += szj
2,613✔
2221
        end
3,809✔
2222
        if c != nc+1
1,417✔
2223
            throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
1✔
2224
        end
2225
        r += szi
1,416✔
2226
        a += rows[i]
1,416✔
2227
    end
1,959✔
2228
    out
873✔
2229
end
2230

2231
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2232
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2233

2234
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,136✔
2235
    nr = length(rows)
1,136✔
2236
    nc = rows[1]
1,136✔
2237

2238
    a = Matrix{T}(undef, nr, nc)
2,272✔
2239
    if length(a) != length(xs)
1,136✔
2240
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2241
    end
2242
    k = 1
1,134✔
2243
    @inbounds for i=1:nr
1,134✔
2244
        if nc != rows[i]
3,139✔
2245
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2246
        end
2247
        for j=1:nc
3,138✔
2248
            a[i,j] = xs[k]
8,632✔
2249
            k += 1
8,632✔
2250
        end
14,126✔
2251
    end
5,143✔
2252
    a
1,133✔
2253
end
2254

2255
function hvcat_fill!(a::Array, xs::Tuple)
475✔
2256
    nr, nc = size(a,1), size(a,2)
483✔
2257
    len = length(xs)
483✔
2258
    if nr*nc != len
483✔
2259
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2260
    end
2261
    k = 1
482✔
2262
    for i=1:nr
482✔
2263
        @inbounds for j=1:nc
1,306✔
2264
            a[i,j] = xs[k]
8,741✔
2265
            k += 1
8,741✔
2266
        end
16,176✔
2267
    end
2,130✔
2268
    a
482✔
2269
end
2270

2271
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
177✔
2272
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
118✔
2273
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2274
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
3✔
2275

2276
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
347✔
2277
    nr = length(rows)
423✔
2278
    nc = rows[1]
423✔
2279
    for i = 2:nr
423✔
2280
        if nc != rows[i]
815✔
2281
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2282
        end
2283
    end
1,205✔
2284
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
421✔
2285
end
2286

2287
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T
133✔
2288
    nbr = length(rows)  # number of block rows
133✔
2289
    rs = Vector{Any}(undef, nbr)
133✔
2290
    a = 1
133✔
2291
    for i = 1:nbr
133✔
2292
        rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...)
328✔
2293
        a += rows[i]
328✔
2294
    end
523✔
2295
    T[rs...;]
133✔
2296
end
2297

2298
## N-dimensional concatenation ##
2299

2300
"""
2301
    hvncat(dim::Int, row_first, values...)
2302
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2303
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2304

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

2307
This function is called for block matrix syntax. The first argument either specifies the
2308
shape of the concatenation, similar to `hvcat`, as a tuple of tuples, or the dimensions that
2309
specify the key number of elements along each axis, and is used to determine the output
2310
dimensions. The `dims` form is more performant, and is used by default when the concatenation
2311
operation has the same number of elements along each axis (e.g., [a b; c d;;; e f ; g h]).
2312
The `shape` form is used when the number of elements along each axis is unbalanced
2313
(e.g., [a b ; c]). Unbalanced syntax needs additional validation overhead. The `dim` form
2314
is an optimization for concatenation along just one dimension. `row_first` indicates how
2315
`values` are ordered. The meaning of the first and second elements of `shape` are also
2316
swapped based on `row_first`.
2317

2318
# Examples
2319
```jldoctest
2320
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2321
(1, 2, 3, 4, 5, 6)
2322

2323
julia> [a b c;;; d e f]
2324
1×3×2 Array{Int64, 3}:
2325
[:, :, 1] =
2326
 1  2  3
2327

2328
[:, :, 2] =
2329
 4  5  6
2330

2331
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2332
2×1×3 Array{Int64, 3}:
2333
[:, :, 1] =
2334
 1
2335
 2
2336

2337
[:, :, 2] =
2338
 3
2339
 4
2340

2341
[:, :, 3] =
2342
 5
2343
 6
2344

2345
julia> [a b;;; c d;;; e f]
2346
1×2×3 Array{Int64, 3}:
2347
[:, :, 1] =
2348
 1  2
2349

2350
[:, :, 2] =
2351
 3  4
2352

2353
[:, :, 3] =
2354
 5  6
2355

2356
julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2357
1×3×2 Array{Int64, 3}:
2358
[:, :, 1] =
2359
 1  2  3
2360

2361
[:, :, 2] =
2362
 4  5  6
2363
```
2364

2365
# Examples for construction of the arguments
2366
```
2367
[a b c ; d e f ;;;
2368
 g h i ; j k l ;;;
2369
 m n o ; p q r ;;;
2370
 s t u ; v w x]
2371
⇒ dims = (2, 3, 4)
2372

2373
[a b ; c ;;; d ;;;;]
2374
 ___   _     _
2375
 2     1     1 = elements in each row (2, 1, 1)
2376
 _______     _
2377
 3           1 = elements in each column (3, 1)
2378
 _____________
2379
 4             = elements in each 3d slice (4,)
2380
 _____________
2381
 4             = elements in each 4d slice (4,)
2382
⇒ shape = ((2, 1, 1), (3, 1), (4,), (4,)) with `row_first` = true
2383
```
2384
"""
2385
hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...)
261✔
2386
hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...)
82✔
2387

2388
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
28✔
2389
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
91✔
2390
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
88✔
2391
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2392
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2393
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
136✔
2394

2395

2396
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
16✔
2397
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2398

2399
# 1-dimensional hvncat methods
2400

2401
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
4✔
2402
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2403
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
4✔
2404
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
4✔
2405
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2406
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
4✔
2407
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2408

2409
_typed_hvncat_0d_only_one() =
8✔
2410
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2411

2412
# `@constprop :aggressive` here to form constant `Val(dim)` type to get type stability
2413
@constprop :aggressive _typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters
82✔
2414

2415
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
15✔
2416
    N < 0 &&
15✔
2417
        throw(ArgumentError("concatenation dimension must be non-negative"))
2418
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
14✔
2419
end
2420

2421
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
26✔
2422
    N < 0 &&
39✔
2423
        throw(ArgumentError("concatenation dimension must be non-negative"))
2424
    A = cat_similar(xs[1], T, (ntuple(x -> 1, Val(N - 1))..., length(xs)))
38✔
2425
    hvncat_fill!(A, false, xs)
38✔
2426
    return A
38✔
2427
end
2428

2429
function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
24✔
2430
    # optimization for arrays that can be concatenated by copying them linearly into the destination
2431
    # conditions: the elements must all have 1-length dimensions above N
2432
    length(as) > 0 ||
26✔
2433
        throw(ArgumentError("must have at least one element"))
2434
    N < 0 &&
26✔
2435
        throw(ArgumentError("concatenation dimension must be non-negative"))
2436
    for a ∈ as
24✔
2437
        ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) ||
62✔
2438
            return _typed_hvncat(T, (ntuple(x -> 1, Val(N - 1))..., length(as), 1), false, as...)
2439
            # the extra 1 is to avoid an infinite cycle
2440
    end
47✔
2441

2442
    nd = N
18✔
2443

2444
    Ndim = 0
18✔
2445
    for i ∈ eachindex(as)
18✔
2446
        Ndim += cat_size(as[i], N)
39✔
2447
        nd = max(nd, cat_ndims(as[i]))
39✔
2448
        for d ∈ 1:N - 1
33✔
2449
            cat_size(as[1], d) == cat_size(as[i], d) || throw(DimensionMismatch("mismatched size along axis $d in element $i"))
40✔
2450
        end
45✔
2451
    end
44✔
2452

2453
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
34✔
2454
    k = 1
14✔
2455
    for a ∈ as
14✔
2456
        for i ∈ eachindex(a)
27✔
2457
            A[k] = a[i]
38✔
2458
            k += 1
38✔
2459
        end
54✔
2460
    end
35✔
2461
    return A
14✔
2462
end
2463

2464
function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
14✔
2465
    length(as) > 0 ||
14✔
2466
        throw(ArgumentError("must have at least one element"))
2467
    N < 0 &&
14✔
2468
        throw(ArgumentError("concatenation dimension must be non-negative"))
2469
    nd = N
12✔
2470
    Ndim = 0
12✔
2471
    for i ∈ eachindex(as)
12✔
2472
        Ndim += cat_size(as[i], N)
30✔
2473
        nd = max(nd, cat_ndims(as[i]))
34✔
2474
        for d ∈ 1:N-1
20✔
2475
            cat_size(as[i], d) == 1 ||
36✔
2476
                throw(DimensionMismatch("all dimensions of element $i other than $N must be of length 1"))
2477
        end
28✔
2478
    end
20✔
2479

2480
    A = Array{T, nd}(undef, ntuple(x -> 1, Val(N - 1))..., Ndim, ntuple(x -> 1, nd - N)...)
7✔
2481

2482
    k = 1
4✔
2483
    for a ∈ as
4✔
2484
        if a isa AbstractArray
12✔
2485
            lena = length(a)
2✔
2486
            copyto!(A, k, a, 1, lena)
2✔
2487
            k += lena
2✔
2488
        else
2489
            A[k] = a
10✔
2490
            k += 1
10✔
2491
        end
2492
    end
16✔
2493
    return A
4✔
2494
end
2495

2496
# 0-dimensional cases for balanced and unbalanced hvncat method
2497

2498
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2499
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2500

2501

2502
# balanced dimensions hvncat methods
2503

2504
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
2✔
2505
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as::Number...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
7✔
2506

2507
function _typed_hvncat_1d(::Type{T}, ds::Int, ::Val{row_first}, as...) where {T, row_first}
21✔
2508
    lengthas = length(as)
22✔
2509
    ds > 0 ||
22✔
2510
        throw(ArgumentError("`dimsshape` argument must consist of positive integers"))
2511
    lengthas == ds ||
30✔
2512
        throw(ArgumentError("number of elements does not match `dimshape` argument; expected $ds, got $lengthas"))
2513
    if row_first
14✔
2514
        return _typed_hvncat(T, Val(2), as...)
4✔
2515
    else
2516
        return _typed_hvncat(T, Val(1), as...)
10✔
2517
    end
2518
end
2519

2520
function _typed_hvncat(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, xs::Number...) where {T, N}
42✔
2521
    all(>(0), dims) ||
58✔
2522
        throw(ArgumentError("`dims` argument must contain positive integers"))
2523
    A = Array{T, N}(undef, dims...)
52✔
2524
    lengtha = length(A)  # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations
26✔
2525
    lengthx = length(xs) # Cuts from 3 allocations to 1.
26✔
2526
    if lengtha != lengthx
26✔
2527
       throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)"))
×
2528
    end
2529
    hvncat_fill!(A, row_first, xs)
26✔
2530
    return A
26✔
2531
end
2532

2533
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
64✔
2534
    nr, nc = size(A, 1), size(A, 2)
64✔
2535
    na = prod(size(A)[3:end])
64✔
2536
    len = length(xs)
64✔
2537
    nrc = nr * nc
64✔
2538
    if nrc * na != len
64✔
2539
        throw(ArgumentError("argument count $(len) does not match specified shape $(size(A))"))
×
2540
    end
2541
    # putting these in separate functions leads to unnecessary allocations
2542
    if row_first
64✔
2543
        k = 1
17✔
2544
        for d ∈ 1:na
17✔
2545
            dd = nrc * (d - 1)
31✔
2546
            for i ∈ 1:nr
31✔
2547
                Ai = dd + i
42✔
2548
                for j ∈ 1:nc
42✔
2549
                    @inbounds A[Ai] = xs[k]
95✔
2550
                    k += 1
95✔
2551
                    Ai += nr
95✔
2552
                end
148✔
2553
            end
53✔
2554
        end
31✔
2555
    else
2556
        for k ∈ eachindex(xs)
47✔
2557
            @inbounds A[k] = xs[k]
92✔
2558
        end
92✔
2559
    end
2560
end
2561

2562
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
76✔
2563
    # function barrier after calculating the max is necessary for high performance
2564
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
90✔
2565
    return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
90✔
2566
end
2567

2568
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
90✔
2569
    length(as) > 0 ||
90✔
2570
        throw(ArgumentError("must have at least one element"))
2571
    all(>(0), dims) ||
122✔
2572
        throw(ArgumentError("`dims` argument must contain positive integers"))
2573

2574
    d1 = row_first ? 2 : 1
58✔
2575
    d2 = row_first ? 1 : 2
58✔
2576

2577
    outdims = zeros(Int, N)
203✔
2578

2579
    # validate shapes for lowest level of concatenation
2580
    d = findfirst(>(1), dims)
86✔
2581
    if d !== nothing # all dims are 1
58✔
2582
        if row_first && d < 3
57✔
2583
            d = d == 1 ? 2 : 1
32✔
2584
        end
2585
        nblocks = length(as) ÷ dims[d]
57✔
2586
        for b ∈ 1:nblocks
57✔
2587
            offset = ((b - 1) * dims[d])
175✔
2588
            startelementi = offset + 1
175✔
2589
            for i ∈ offset .+ (2:dims[d])
263✔
2590
                for dd ∈ 1:N
111✔
2591
                    dd == d && continue
316✔
2592
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
313✔
2593
                        throw(DimensionMismatch("incompatible shape in element $i"))
6✔
2594
                    end
2595
                end
515✔
2596
            end
129✔
2597
        end
287✔
2598
    end
2599

2600
    # discover number of rows or columns
2601
    for i ∈ 1:dims[d1]
52✔
2602
        outdims[d1] += cat_size(as[i], d1)
108✔
2603
    end
164✔
2604

2605
    currentdims = zeros(Int, N)
176✔
2606
    blockcount = 0
52✔
2607
    elementcount = 0
52✔
2608
    for i ∈ eachindex(as)
52✔
2609
        elementcount += cat_length(as[i])
306✔
2610
        currentdims[d1] += cat_size(as[i], d1)
259✔
2611
        if currentdims[d1] == outdims[d1]
259✔
2612
            currentdims[d1] = 0
129✔
2613
            for d ∈ (d2, 3:N...)
129✔
2614
                currentdims[d] += cat_size(as[i], d)
203✔
2615
                if outdims[d] == 0 # unfixed dimension
203✔
2616
                    blockcount += 1
167✔
2617
                    if blockcount == dims[d]
167✔
2618
                        outdims[d] = currentdims[d]
88✔
2619
                        currentdims[d] = 0
88✔
2620
                        blockcount = 0
88✔
2621
                    else
2622
                        break
79✔
2623
                    end
2624
                else # fixed dimension
2625
                    if currentdims[d] == outdims[d] # end of dimension
36✔
2626
                        currentdims[d] = 0
23✔
2627
                    elseif currentdims[d] < outdims[d] # dimension in progress
13✔
2628
                        break
13✔
2629
                    else # exceeded dimension
2630
                        throw(DimensionMismatch("argument $i has too many elements along axis $d"))
×
2631
                    end
2632
                end
2633
            end
142✔
2634
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
130✔
2635
            throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
16✔
2636
        end
2637
    end
450✔
2638

2639
    outlen = prod(outdims)
72✔
2640
    elementcount == outlen ||
36✔
2641
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2642

2643
    # copy into final array
2644
    A = cat_similar(as[1], T, outdims)
36✔
2645
    # @assert all(==(0), currentdims)
2646
    outdims .= 0
108✔
2647
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
36✔
2648
    return A
36✔
2649
end
2650

2651

2652
# unbalanced dimensions hvncat methods
2653

2654
function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
19✔
2655
    length(shape[1]) > 0 ||
19✔
2656
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2657
    return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
13✔
2658
end
2659

2660
function _typed_hvncat(T::Type, shape::NTuple{N, Tuple}, row_first::Bool, as...) where {N}
99✔
2661
    # function barrier after calculating the max is necessary for high performance
2662
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
115✔
2663
    return _typed_hvncat_shape(T, (shape..., ntuple(x -> shape[end], nd - N)...), row_first, as)
122✔
2664
end
2665

2666
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
107✔
2667
    length(as) > 0 ||
107✔
2668
        throw(ArgumentError("must have at least one element"))
2669
    all(>(0), tuple((shape...)...)) ||
147✔
2670
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2671

2672
    d1 = row_first ? 2 : 1
67✔
2673
    d2 = row_first ? 1 : 2
67✔
2674

2675
    shapev = collect(shape) # saves allocations later
110✔
2676
    all(!isempty, shapev) ||
67✔
2677
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2678
    length(shapev[end]) == 1 ||
70✔
2679
        throw(ArgumentError("last level of shape must contain only one integer"))
2680
    shapelength = shapev[end][1]
64✔
2681
    lengthas = length(as)
64✔
2682
    shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)"))
64✔
2683
    # discover dimensions
2684
    nd = max(N, cat_ndims(as[1]))
64✔
2685
    outdims = fill(-1, nd)
210✔
2686
    currentdims = zeros(Int, nd)
210✔
2687
    blockcounts = zeros(Int, nd)
210✔
2688
    shapepos = ones(Int, nd)
210✔
2689

2690
    elementcount = 0
64✔
2691
    for i ∈ eachindex(as)
64✔
2692
        elementcount += cat_length(as[i])
355✔
2693
        wasstartblock = false
313✔
2694
        for d ∈ 1:N
313✔
2695
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
907✔
2696
            dsize = cat_size(as[i], ad)
1,386✔
2697
            blockcounts[d] += 1
907✔
2698

2699
            if d == 1 || i == 1 || wasstartblock
1,501✔
2700
                currentdims[d] += dsize
623✔
2701
            elseif dsize != cat_size(as[i - 1], ad)
422✔
2702
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
8✔
2703
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2704
            end
2705

2706
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
899✔
2707

2708
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
899✔
2709
            if isendblock
899✔
2710
                if outdims[d] == -1
269✔
2711
                    outdims[d] = currentdims[d]
138✔
2712
                elseif outdims[d] != currentdims[d]
131✔
2713
                    throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
40✔
2714
                                             expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2715
                end
2716
                currentdims[d] = 0
229✔
2717
                blockcounts[d] = 0
229✔
2718
                shapepos[d] += 1
229✔
2719
                d > 1 && (blockcounts[d - 1] == 0 ||
230✔
2720
                    throw(DimensionMismatch("shape in level $d is inconsistent; level counts must nest \
2721
                                             evenly into each other")))
2722
            end
2723
        end
1,452✔
2724
    end
513✔
2725

2726
    outlen = prod(outdims)
30✔
2727
    elementcount == outlen ||
15✔
2728
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2729

2730
    if row_first
15✔
2731
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2732
    end
2733

2734
    # @assert all(==(0), currentdims)
2735
    # @assert all(==(0), blockcounts)
2736

2737
    # copy into final array
2738
    A = cat_similar(as[1], T, outdims)
15✔
2739
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
15✔
2740
    return A
15✔
2741
end
2742

2743
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int},
51✔
2744
                              d1::Int, d2::Int, as::Tuple) where {T, N}
2745
    N > 1 || throw(ArgumentError("dimensions of the destination array must be at least 2"))
51✔
2746
    length(scratch1) == length(scratch2) == N ||
51✔
2747
        throw(ArgumentError("scratch vectors must have as many elements as the destination array has dimensions"))
2748
    0 < d1 < 3 &&
51✔
2749
    0 < d2 < 3 &&
2750
    d1 != d2 ||
2751
        throw(ArgumentError("d1 and d2 must be either 1 or 2, exclusive."))
2752
    outdims = size(A)
51✔
2753
    offsets = scratch1
51✔
2754
    inneroffsets = scratch2
51✔
2755
    for a ∈ as
51✔
2756
        if isa(a, AbstractArray)
270✔
2757
            for ai ∈ a
249✔
2758
                @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
7,046✔
2759
                A[Ai] = ai
1,888✔
2760

2761
                @inbounds for j ∈ 1:N
1,888✔
2762
                    inneroffsets[j] += 1
4,152✔
2763
                    inneroffsets[j] < cat_size(a, j) && break
7,976✔
2764
                    inneroffsets[j] = 0
2,490✔
2765
                end
2,490✔
2766
            end
1,912✔
2767
        else
2768
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2769
            A[Ai] = a
27✔
2770
        end
2771

2772
        @inbounds for j ∈ (d1, d2, 3:N...)
270✔
2773
            offsets[j] += cat_size(a, j)
518✔
2774
            offsets[j] < outdims[j] && break
518✔
2775
            offsets[j] = 0
304✔
2776
        end
304✔
2777
    end
270✔
2778
end
2779

2780
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
2781
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2782
    Ai = inneroffsets[1] + offsets[1] + 1
1,915✔
2783
    for j ∈ 2:nd
1,915✔
2784
        increment = inneroffsets[j] + offsets[j]
7,098✔
2785
        for k ∈ 1:j-1
7,098✔
2786
            increment *= outdims[k]
17,209✔
2787
        end
27,320✔
2788
        Ai += increment
7,098✔
2789
    end
12,281✔
2790
    Ai
1,915✔
2791
end
2792

2793
"""
2794
    stack(iter; [dims])
2795

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

2799
By default the axes of the elements are placed first,
2800
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2801
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2802

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

2807
The various [`cat`](@ref) functions also combine arrays. However, these all
2808
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2809
the arrays along new dimensions.
2810
They also accept arrays as separate arguments, rather than a single collection.
2811

2812
!!! compat "Julia 1.9"
2813
    This function requires at least Julia 1.9.
2814

2815
# Examples
2816
```jldoctest
2817
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2818

2819
julia> mat = stack(vecs)
2820
2×3 Matrix{Float32}:
2821
 1.0  30.0  500.0
2822
 2.0  40.0  600.0
2823

2824
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2825
true
2826

2827
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2828
true
2829

2830
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2831
2×4 Matrix{Int64}:
2832
  1   2   3   4
2833
 10  11  12  13
2834

2835
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2836
true
2837

2838
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2839
3×2 Matrix{Float32}:
2840
   1.0    2.0
2841
  30.0   40.0
2842
 500.0  600.0
2843

2844
julia> x = rand(3,4);
2845

2846
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2847
true
2848
```
2849

2850
Higher-dimensional examples:
2851

2852
```jldoctest
2853
julia> A = rand(5, 7, 11);
2854

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

2857
julia> (element = size(first(E)), container = size(E))
2858
(element = (5, 11), container = (7,))
2859

2860
julia> stack(E) |> size
2861
(5, 11, 7)
2862

2863
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2864
true
2865

2866
julia> A == stack(E; dims=2)
2867
true
2868

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

2871
julia> (element = size(first(M)), container = size(M))
2872
(element = (2, 3), container = (5, 7))
2873

2874
julia> stack(M) |> size  # keeps all dimensions
2875
(2, 3, 5, 7)
2876

2877
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2878
(35, 2, 3)
2879

2880
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2881
(14, 15)
2882
```
2883
"""
2884
stack(iter; dims=:) = _stack(dims, iter)
258✔
2885

2886
"""
2887
    stack(f, args...; [dims])
2888

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

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

2896
See also [`mapslices`](@ref), [`eachcol`](@ref).
2897

2898
# Examples
2899
```jldoctest
2900
julia> stack(c -> (c, c-32), "julia")
2901
2×5 Matrix{Char}:
2902
 'j'  'u'  'l'  'i'  'a'
2903
 'J'  'U'  'L'  'I'  'A'
2904

2905
julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2906
         vcat(row, row .* n, row ./ n)
2907
       end
2908
2×9 Matrix{Float64}:
2909
 1.0  2.0  3.0   10.0   20.0   30.0  0.1   0.2   0.3
2910
 4.0  5.0  6.0  400.0  500.0  600.0  0.04  0.05  0.06
2911
```
2912
"""
2913
stack(f, iter; dims=:) = _stack(dims, f(x) for x in iter)
12✔
2914
stack(f, xs, yzs...; dims=:) = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
2✔
2915

2916
_stack(dims::Union{Integer, Colon}, iter) = _stack(dims, IteratorSize(iter), iter)
171✔
2917

2918
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2919

2920
function _stack(dims, ::Union{HasShape, HasLength}, iter)
33✔
2921
    S = @default_eltype iter
124✔
2922
    T = S != Union{} ? eltype(S) : Any  # Union{} occurs for e.g. stack(1,2), postpone the error
124✔
2923
    if isconcretetype(T)
124✔
2924
        _typed_stack(dims, T, S, iter)
111✔
2925
    else  # Need to look inside, but shouldn't run an expensive iterator twice:
2926
        array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
38✔
2927
        isempty(array) && return _empty_stack(dims, T, S, iter)
38✔
2928
        T2 = mapreduce(eltype, promote_type, array)
35✔
2929
        _typed_stack(dims, T2, eltype(array), array)
36✔
2930
    end
2931
end
2932

2933
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
114✔
2934
    xit = iterate(A)
221✔
2935
    nothing === xit && return _empty_stack(:, T, S, A)
96✔
2936
    x1, _ = xit
96✔
2937
    ax1 = _iterator_axes(x1)
100✔
2938
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
177✔
2939
    off = firstindex(B)
95✔
2940
    len = length(x1)
101✔
2941
    while xit !== nothing
2,568✔
2942
        x, state = xit
2,480✔
2943
        _stack_size_check(x, ax1)
4,661✔
2944
        copyto!(B, off, x)
3,567✔
2945
        off += len
2,473✔
2946
        xit = iterate(A, state)
3,740✔
2947
    end
2,473✔
2948
    B
88✔
2949
end
2950

2951
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,256✔
2952
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
471✔
2953
_iterator_axes(x, ::IteratorSize) = axes(x)
8,785✔
2954

2955
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2956
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
48✔
2957
    _typed_stack(dims, T, S, IteratorSize(S), A)
2958
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
13✔
2959
    _typed_stack(dims, T, S, HasShape{1}(), A)
2960
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
1✔
2961
    if dims == N+1
27✔
2962
        _typed_stack(:, T, S, A, (_vec_axis(A),))
4✔
2963
    else
2964
        _dim_stack(dims, T, S, A)
23✔
2965
    end
2966
end
2967
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
2✔
2968
    _dim_stack(dims, T, S, A)
2969

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

2972
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
25✔
2973
    xit = Iterators.peel(A)
48✔
2974
    nothing === xit && return _empty_stack(dims, T, S, A)
25✔
2975
    x1, xrest = xit
25✔
2976
    ax1 = _iterator_axes(x1)
25✔
2977
    N1 = length(ax1)+1
24✔
2978
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
27✔
2979

2980
    newaxis = _vec_axis(A)
21✔
2981
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
124✔
2982
    B = similar(_ensure_array(x1), T, outax...)
41✔
2983

2984
    if dims == 1
21✔
2985
        _dim_stack!(Val(1), B, x1, xrest)
13✔
2986
    elseif dims == 2
8✔
2987
        _dim_stack!(Val(2), B, x1, xrest)
4✔
2988
    else
2989
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
2990
    end
2991
    B
18✔
2992
end
2993

2994
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
20✔
2995
    before = ntuple(d -> Colon(), dims - 1)
29✔
2996
    after = ntuple(d -> Colon(), ndims(B) - dims)
42✔
2997

2998
    i = firstindex(B, dims)
21✔
2999
    copyto!(view(B, before..., i, after...), x1)
37✔
3000

3001
    for x in xrest
29✔
3002
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
3003
        i += 1
3,261✔
3004
        @inbounds copyto!(view(B, before..., i, after...), x)
6,393✔
3005
    end
3,261✔
3006
end
3007

3008
@inline function _stack_size_check(x, ax1::Tuple)
26✔
3009
    if _iterator_axes(x) != ax1
11,114✔
3010
        uax1 = map(UnitRange, ax1)
10✔
3011
        uaxN = map(UnitRange, _iterator_axes(x))
10✔
3012
        throw(DimensionMismatch(
10✔
3013
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
3014
    end
3015
end
3016

3017
_ensure_array(x::AbstractArray) = x
85✔
3018
_ensure_array(x) = 1:0  # passed to similar, makes stack's output an Array
31✔
3019

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

3022

3023
## Reductions and accumulates ##
3024

3025
function isequal(A::AbstractArray, B::AbstractArray)
246,508✔
3026
    if A === B return true end
288,989✔
3027
    if axes(A) != axes(B)
574,590✔
3028
        return false
2,924✔
3029
    end
3030
    for (a, b) in zip(A, B)
571,109✔
3031
        if !isequal(a, b)
91,936,739✔
3032
            return false
684✔
3033
        end
3034
    end
183,463,731✔
3035
    return true
285,158✔
3036
end
3037

3038
function cmp(A::AbstractVector, B::AbstractVector)
12✔
3039
    for (a, b) in zip(A, B)
286✔
3040
        if !isequal(a, b)
183✔
3041
            return isless(a, b) ? -1 : 1
185✔
3042
        end
3043
    end
99✔
3044
    return cmp(length(A), length(B))
19✔
3045
end
3046

3047
"""
3048
    isless(A::AbstractVector, B::AbstractVector)
3049

3050
Return `true` when `A` is less than `B` in lexicographic order.
3051
"""
3052
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
199✔
3053

3054
function (==)(A::AbstractArray, B::AbstractArray)
6,425,668✔
3055
    if axes(A) != axes(B)
12,893,596✔
3056
        return false
3,983✔
3057
    end
3058
    anymissing = false
6,437,108✔
3059
    for (a, b) in zip(A, B)
12,002,766✔
3060
        eq = (a == b)
280,774,466✔
3061
        if ismissing(eq)
277,254,778✔
3062
            anymissing = true
24✔
3063
        elseif !eq
280,770,802✔
3064
            return false
2,964✔
3065
        end
3066
    end
555,980,649✔
3067
    return anymissing ? missing : true
6,441,925✔
3068
end
3069

3070
# _sub2ind and _ind2sub
3071
# fallbacks
3072
function _sub2ind(A::AbstractArray, I...)
276✔
3073
    @inline
267,425,935✔
3074
    _sub2ind(axes(A), I...)
283,763,571✔
3075
end
3076

3077
function _ind2sub(A::AbstractArray, ind)
3078
    @inline
443,626✔
3079
    _ind2sub(axes(A), ind)
443,626✔
3080
end
3081

3082
# 0-dimensional arrays and indexing with []
3083
_sub2ind(::Tuple{}) = 1
×
3084
_sub2ind(::DimsInteger) = 1
×
3085
_sub2ind(::Indices) = 1
×
3086
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
3✔
3087

3088
# Generic cases
3089
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
654,297✔
3090
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
283,763,571✔
3091
# In 1d, there's a question of whether we're doing cartesian indexing
3092
# or linear indexing. Support only the former.
3093
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
3094
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3095
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
3096
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
3097

3098
_sub2ind_recurse(::Any, L, ind) = ind
44,482✔
3099
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
360✔
3100
    @inline
1,159✔
3101
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
67,863✔
3102
end
3103
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
870✔
3104
    @inline
12,281,138✔
3105
    r1 = inds[1]
12,346,251✔
3106
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
579,863,191✔
3107
end
3108

3109
nextL(L, l::Integer) = L*l
494,913✔
3110
nextL(L, r::AbstractUnitRange) = L*length(r)
294,855,594✔
3111
nextL(L, r::Slice) = L*length(r.indices)
×
3112
offsetin(i, l::Integer) = i-1
1,083,964✔
3113
offsetin(i, r::AbstractUnitRange) = i-first(r)
578,641,318✔
3114

3115
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
3116
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
×
3117
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
443,623✔
3118
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
3119
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3120
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
63✔
3121

3122
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3123
function _ind2sub_recurse(indslast::NTuple{1}, ind)
3124
    @inline
443,623✔
3125
    (_lookup(ind, indslast[1]),)
443,623✔
3126
end
3127
function _ind2sub_recurse(inds, ind)
3128
    @inline
789,772✔
3129
    r1 = inds[1]
789,772✔
3130
    indnext, f, l = _div(ind, r1)
789,772✔
3131
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
789,772✔
3132
end
3133

3134
_lookup(ind, d::Integer) = ind+1
×
3135
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
443,623✔
3136
_div(ind, d::Integer) = div(ind, d), 1, d
×
3137
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
789,772✔
3138

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

3158
function _sub2ind!(Iout, inds, Iinds, I)
×
3159
    @noinline
×
3160
    for i in Iinds
×
3161
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3162
        Iout[i] = sub2ind_vec(inds, i, I)
×
3163
    end
×
3164
    Iout
×
3165
end
3166

3167
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3168
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3169
_sub2ind_vec(i) = ()
×
3170

3171
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3172
    M = length(ind)
×
3173
    t = ntuple(n->similar(ind),Val(N))
×
3174
    for (i,idx) in pairs(IndexLinear(), ind)
×
3175
        sub = _ind2sub(inds, idx)
×
3176
        for j = 1:N
×
3177
            t[j][i] = sub[j]
×
3178
        end
×
3179
    end
×
3180
    t
×
3181
end
3182

3183
## iteration utilities ##
3184

3185
"""
3186
    foreach(f, c...) -> Nothing
3187

3188
Call function `f` on each element of iterable `c`.
3189
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3190
any iterator is finished.
3191

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

3195
# Examples
3196
```jldoctest
3197
julia> tri = 1:3:7; res = Int[];
3198

3199
julia> foreach(x -> push!(res, x^2), tri)
3200

3201
julia> res
3202
3-element Vector{$(Int)}:
3203
  1
3204
 16
3205
 49
3206

3207
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3208
1 with a
3209
4 with b
3210
7 with c
3211
```
3212
"""
3213
foreach(f, itr) = (for x in itr; f(x); end; nothing)
433,516,418✔
3214
foreach(f, itr, itrs...) = (for z in zip(itr, itrs...); f(z...); end; nothing)
1✔
3215

3216
## map over arrays ##
3217

3218
## transform any set of dimensions
3219
## dims specifies which dimensions will be transformed. for example
3220
## dims==1:2 will call f on all slices A[:,:,...]
3221
"""
3222
    mapslices(f, A; dims)
3223

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

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

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

3233
# Examples
3234
```jldoctest
3235
julia> A = reshape(1:30,(2,5,3))
3236
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3237
[:, :, 1] =
3238
 1  3  5  7   9
3239
 2  4  6  8  10
3240

3241
[:, :, 2] =
3242
 11  13  15  17  19
3243
 12  14  16  18  20
3244

3245
[:, :, 3] =
3246
 21  23  25  27  29
3247
 22  24  26  28  30
3248

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

3251
julia> B = mapslices(f, A, dims=(1,2))
3252
1×4×3 Array{$Int, 3}:
3253
[:, :, 1] =
3254
 1  1  1  1
3255

3256
[:, :, 2] =
3257
 11  11  11  11
3258

3259
[:, :, 3] =
3260
 21  21  21  21
3261

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

3264
julia> B == stack(f2, eachslice(A, dims=3))
3265
true
3266

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

3269
julia> mapslices(g, A, dims=[1,3])
3270
1×5×1 Array{Rational{$Int}, 3}:
3271
[:, :, 1] =
3272
 1//21  3//23  1//5  7//27  9//29
3273

3274
julia> map(g, eachslice(A, dims=2))
3275
5-element Vector{Rational{$Int}}:
3276
 1//21
3277
 3//23
3278
 1//5
3279
 7//27
3280
 9//29
3281

3282
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3283
true
3284
```
3285

3286
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3287
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3288
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3289
values in the slice without affecting `A`.
3290
"""
3291
@constprop :aggressive function mapslices(f, A::AbstractArray; dims)
822✔
3292
    isempty(dims) && return map(f, A)
411✔
3293

3294
    for d in dims
532✔
3295
        d isa Integer || throw(ArgumentError("mapslices: dimension must be an integer, got $d"))
831✔
3296
        d >= 1 || throw(ArgumentError("mapslices: dimension must be ≥ 1, got $d"))
831✔
3297
        # Indexing a matrix M[:,1,:] produces a 1-column matrix, but dims=(1,3) here
3298
        # would otherwise ignore 3, and slice M[:,i]. Previously this gave error:
3299
        # BoundsError: attempt to access 2-element Vector{Any} at index [3]
3300
        d > ndims(A) && throw(ArgumentError("mapslices does not accept dimensions > ndims(A) = $(ndims(A)), got $d"))
831✔
3301
    end
831✔
3302
    dim_mask = ntuple(d -> d in dims, ndims(A))
1,886✔
3303

3304
    # Apply the function to the first slice in order to determine the next steps
3305
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3,002✔
3306
    Aslice = A[idx1...]
486✔
3307
    r1 = f(Aslice)
429✔
3308

3309
    res1 = if r1 isa AbstractArray && ndims(r1) > 0
411✔
3310
        n = sum(dim_mask)
4✔
3311
        if ndims(r1) > n && any(ntuple(d -> size(r1,d+n)>1, ndims(r1)-n))
4✔
3312
            s = size(r1)[1:n]
×
3313
            throw(DimensionMismatch("mapslices cannot assign slice f(x) of size $(size(r1)) into output of size $s"))
×
3314
        end
3315
        r1
4✔
3316
    else
3317
        # If the result of f on a single slice is a scalar then we add singleton
3318
        # dimensions. When adding the dimensions, we have to respect the
3319
        # index type of the input array (e.g. in the case of OffsetArrays)
3320
        _res1 = similar(Aslice, typeof(r1), reduced_indices(Aslice, 1:ndims(Aslice)))
407✔
3321
        _res1[begin] = r1
407✔
3322
        _res1
799✔
3323
    end
3324

3325
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3326
    din = Ref(0)
411✔
3327
    Rsize = ntuple(ndims(A)) do d
805✔
3328
        if d in dims
3,118✔
3329
            axes(res1, din[] += 1)
831✔
3330
        else
3331
            axes(A,d)
775✔
3332
        end
3333
    end
3334
    R = similar(res1, Rsize)
415✔
3335

3336
    # Determine iteration space. It will be convenient in the loop to mask N-dimensional
3337
    # CartesianIndices, with some trivial dimensions:
3338
    itershape = ntuple(d -> d in dims ? Base.OneTo(1) : axes(A,d), ndims(A))
3,002✔
3339
    indices = Iterators.drop(CartesianIndices(itershape), 1)
411✔
3340

3341
    # That skips the first element, which we already have:
3342
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
3,189✔
3343
    concatenate_setindex!(R, res1, ridx...)
420✔
3344

3345
    # In some cases, we can re-use the first slice for a dramatic performance
3346
    # increase. The slice itself must be mutable and the result cannot contain
3347
    # any mutable containers. The following errs on the side of being overly
3348
    # strict (#18570 & #21123).
3349
    safe_for_reuse = isa(Aslice, StridedArray) &&
411✔
3350
                     (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number))
3351

3352
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
419✔
3353
    return R
411✔
3354
end
3355

3356
@noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
411✔
3357
    must_extend = any(dim_mask .& size(R) .> 1)
1,979✔
3358
    if safe_for_reuse
411✔
3359
        # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3360
        # so we can reuse Aslice
3361
        for I in indices
704✔
3362
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
11,111✔
3363
            _unsafe_getindex!(Aslice, A, idx...)
11,111✔
3364
            r = f(Aslice)
16,631✔
3365
            if r isa AbstractArray || must_extend
11,111✔
3366
                ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
6✔
3367
                R[ridx...] = r
12✔
3368
            else
3369
                ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
11,105✔
3370
                R[ridx...] = r
11,105✔
3371
            end
3372
        end
11,111✔
3373
    else
3374
        # we can't guarantee safety (#18524), so allocate new storage for each slice
3375
        for I in indices
118✔
3376
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
1,852✔
3377
            ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
1,852✔
3378
            concatenate_setindex!(R, f(A[idx...]), ridx...)
3,704✔
3379
        end
1,852✔
3380
    end
3381
end
3382

3383
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
1,846✔
3384
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
422✔
3385

3386
## 1 argument
3387

3388
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
1,282✔
3389
    for (i,j) in zip(eachindex(dest),eachindex(A))
664,178,207✔
3390
        val = f(@inbounds A[j])
562,637,636✔
3391
        @inbounds dest[i] = val
407,659,685✔
3392
    end
503,424,626✔
3393
    return dest
352,283,463✔
3394
end
3395

3396
# map on collections
3397
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
195,225✔
3398

3399
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
1,764✔
3400
mapany(f, itr) = Any[f(x) for x in itr]
×
3401

3402
"""
3403
    map(f, c...) -> collection
3404

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

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

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

3412
# Examples
3413
```jldoctest
3414
julia> map(x -> x * 2, [1, 2, 3])
3415
3-element Vector{Int64}:
3416
 2
3417
 4
3418
 6
3419

3420
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3421
3-element Vector{Int64}:
3422
 11
3423
 22
3424
 33
3425
```
3426
"""
3427
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
159✔
3428

3429
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3430
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3431

3432
## 2 argument
3433
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
304✔
3434
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
727✔
3435
        @inbounds a, b = A[j], B[k]
338,222✔
3436
        val = f(a, b)
338,222✔
3437
        @inbounds dest[i] = val
338,222✔
3438
    end
676,087✔
3439
    return dest
370✔
3440
end
3441

3442
## N argument
3443

3444
@inline ith_all(i, ::Tuple{}) = ()
4,020✔
3445
function ith_all(i, as)
3446
    @_propagate_inbounds_meta
12,060✔
3447
    return (as[1][i], ith_all(i, tail(as))...)
12,060✔
3448
end
3449

3450
function map_n!(f::F, dest::AbstractArray, As) where F
45✔
3451
    idxs1 = LinearIndices(As[1])
45✔
3452
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
360✔
3453
    for i = idxs1
45✔
3454
        @inbounds I = ith_all(i, As)
4,020✔
3455
        val = f(I...)
4,020✔
3456
        @inbounds dest[i] = val
4,020✔
3457
    end
7,995✔
3458
    return dest
45✔
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}
43✔
3493
    isempty(As) && throw(ArgumentError(
46✔
3494
        """map! requires at least one "source" argument"""))
3495
    map_n!(f, dest, As)
45✔
3496
end
3497

3498
"""
3499
    map(f, A::AbstractArray...) -> N-array
3500

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

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

3506
# Examples
3507
```
3508
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3509
2×2 Matrix{Rational{$Int}}:
3510
 1//4  2//3
3511
 3//2  4//1
3512

3513
julia> map(+, [1 2; 3 4], zeros(2,1))
3514
ERROR: DimensionMismatch
3515

3516
julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1))  # iterates until 3rd is exhausted
3517
3-element Vector{Float64}:
3518
   2.0
3519
  13.0
3520
 102.0
3521
```
3522
"""
3523
map(f, it, iters...) = collect(Generator(f, it, iters...))
1,255✔
3524

3525
# Generic versions of push! for AbstractVector
3526
# These are specialized further for Vector for faster resizing and setindexing
3527
function push!(a::AbstractVector{T}, item) where T
10✔
3528
    # convert first so we don't grow the array if the assignment won't work
3529
    itemT = item isa T ? item : convert(T, item)::T
21✔
3530
    new_length = length(a) + 1
13✔
3531
    resize!(a, new_length)
13✔
3532
    a[end] = itemT
13✔
3533
    return a
13✔
3534
end
3535

3536
# specialize and optimize the single argument case
3537
function push!(a::AbstractVector{Any}, @nospecialize x)
1✔
3538
    new_length = length(a) + 1
7✔
3539
    resize!(a, new_length)
7✔
3540
    a[end] = x
7✔
3541
    return a
7✔
3542
end
3543
function push!(a::AbstractVector{Any}, @nospecialize x...)
2✔
3544
    @_terminates_locally_meta
2✔
3545
    na = length(a)
2✔
3546
    nx = length(x)
2✔
3547
    resize!(a, na + nx)
2✔
3548
    e = lastindex(a) - nx
2✔
3549
    for i = 1:nx
2✔
3550
        a[e+i] = x[i]
5✔
3551
    end
8✔
3552
    return a
2✔
3553
end
3554

3555
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3556
# (note: must not cause a dispatch loop when 1-item case is not defined)
3557
push!(A, a, b) = push!(push!(A, a), b)
995✔
3558
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
2✔
3559
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3560
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
2✔
3561

3562
# sizehint! does not nothing by default
3563
sizehint!(a::AbstractVector, _) = a
19✔
3564

3565
## hashing AbstractArray ##
3566

3567
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3568
function hash(A::AbstractArray, h::UInt)
17,104✔
3569
    h += hash_abstractarray_seed
17,104✔
3570
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3571
    # Instead hash the tuple of firsts and lasts along each dimension
3572
    h = hash(map(first, axes(A)), h)
17,341✔
3573
    h = hash(map(last, axes(A)), h)
17,341✔
3574

3575
    # For short arrays, it's not worth doing anything complicated
3576
    if length(A) < 8192
17,341✔
3577
        for x in A
22,139✔
3578
            h = hash(x, h)
2,365,320✔
3579
        end
2,252,242✔
3580
        return h
17,100✔
3581
    end
3582

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

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

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

3604
    # Start at the last index
3605
    keyidx = last(ks)
4✔
3606
    linidx = key_to_linear[keyidx]
4✔
3607
    fibskip = prevfibskip = oneunit(linidx)
4✔
3608
    first_linear = first(LinearIndices(linear_to_key))
4✔
3609
    n = 0
4✔
3610
    while true
28,192✔
3611
        n += 1
28,192✔
3612
        # Hash the element
3613
        elt = A[keyidx]
28,192✔
3614
        h = hash(keyidx=>elt, h)
28,192✔
3615

3616
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3617
        linidx = key_to_linear[keyidx]
28,192✔
3618
        linidx < fibskip + first_linear && break
28,192✔
3619
        linidx -= fibskip
28,188✔
3620
        keyidx = linear_to_key[linidx]
28,188✔
3621

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

3632
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3633
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3634
        keyidx === nothing && break
28,188✔
3635
    end
28,188✔
3636

3637
    return h
4✔
3638
end
3639

3640
# The semantics of `collect` are weird. Better to write our own
3641
function rest(a::AbstractArray{T}, state...) where {T}
5✔
3642
    v = Vector{T}(undef, 0)
11✔
3643
    # assume only very few items are taken from the front
3644
    sizehint!(v, length(a))
11✔
3645
    return foldl(push!, Iterators.rest(a, state...), init=v)
11✔
3646
end
3647

3648

3649
## keepat! ##
3650

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

3653
function _keepat!(a::AbstractVector, inds)
7✔
3654
    local prev
11✔
3655
    i = firstindex(a)
11✔
3656
    for k in inds
17✔
3657
        if @isdefined(prev)
34✔
3658
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
27✔
3659
        end
3660
        ak = a[k] # must happen even when i==k for bounds checking
35✔
3661
        if i != k
29✔
3662
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
13✔
3663
        end
3664
        prev = k
29✔
3665
        i = nextind(a, i)
29✔
3666
    end
50✔
3667
    deleteat!(a, i:lastindex(a))
11✔
3668
    return a
6✔
3669
end
3670

3671
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
×
3672
    length(m) == length(a) || throw(BoundsError(a, m))
×
3673
    j = firstindex(a)
×
3674
    for i in eachindex(a, m)
×
3675
        @inbounds begin
×
3676
            if m[i]
×
3677
                i == j || (a[j] = a[i])
×
3678
                j = nextind(a, j)
×
3679
            end
3680
        end
3681
    end
×
3682
    deleteat!(a, j:lastindex(a))
×
3683
end
3684

3685
## 1-d circshift ##
3686
function circshift!(a::AbstractVector, shift::Integer)
1,116✔
3687
    n = length(a)
1,134✔
3688
    n == 0 && return a
1,134✔
3689
    shift = mod(shift, n)
2,268✔
3690
    shift == 0 && return a
1,134✔
3691
    l = lastindex(a)
668✔
3692
    reverse!(a, firstindex(a), l-shift)
668✔
3693
    reverse!(a, l-shift+1, lastindex(a))
668✔
3694
    reverse!(a)
668✔
3695
    return a
668✔
3696
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