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

JuliaLang / julia / #37865

08 Aug 2024 11:44PM UTC coverage: 86.076% (-1.5%) from 87.613%
#37865

push

local

web-flow
Vendor the terminfo database for use with base/terminfo.jl (#55411)

This adds the `terminfo` database to `deps/`, providing a better user
experience on systems that don't have `terminfo` on the system by
default. The database is built using BinaryBuilder but is not actually
platform-specific (it's built for `AnyPlatform`) and as such, this
fetches the artifact directly rather than adding a new JLL to stdlib,
and it requires no compilation.

A build flag, `WITH_TERMINFO`, is added here and assumed true by
default, allowing users to set `WITH_TERMINFO=0` in Make.user to avoid
bundling `terminfo` should they want to do so.

The lookup policy for `terminfo` entries is still compliant with what's
described in `terminfo(5)`; the bundled directory is taken to be the
first "compiled in" location, i.e. prepended to `@TERMINFO_DIRS@`. This
allows any user settings that exist locally, such as custom entries or
locations, to take precedence.

Fixes #55274

Co-authored-by: Mosè Giordano <giordano@users.noreply.github.com>

1 of 4 new or added lines in 1 file covered. (25.0%)

2056 existing lines in 57 files now uncovered.

76330 of 88677 relevant lines covered (86.08%)

15164230.56 hits per line

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

90.49
/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
59,627✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
5,292✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
8,337✔
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
961,271✔
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}
235✔
76
    @inline
70,935,763✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
70,996,947✔
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,111✔
97
    @inline
609,746,760✔
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)...)
841,222✔
112
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
419,502✔
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,547,633✔
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,855,804✔
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))
28,695✔
166
keys(a::AbstractVector) = LinearIndices(a)
81,705,504✔
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))
21,840,161✔
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
9,751✔
216
nextind(::AbstractArray, i::Integer) = Int(i)+1
301,887,778✔
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))
30,952,117✔
242
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
29,877,341✔
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))
97,755,935✔
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,955,280✔
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)))
40,384,895✔
316

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

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

323

324
@noinline function throw_eachindex_mismatch_indices(::IndexLinear, inds...)
1✔
325
    throw(DimensionMismatch("all inputs to eachindex must have the same indices, got $(join(inds, ", ", " and "))"))
1✔
326
end
327
@noinline function throw_eachindex_mismatch_indices(::IndexCartesian, inds...)
1✔
328
    throw(DimensionMismatch("all inputs to eachindex must have the same axes, got $(join(inds, ", ", " and "))"))
1✔
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))
348,005✔
379

380
function eachindex(A::AbstractArray, B::AbstractArray)
7✔
381
    @inline
38✔
382
    eachindex(IndexStyle(A,B), A, B)
38✔
383
end
384
function eachindex(A::AbstractArray, B::AbstractArray...)
2✔
385
    @inline
2✔
386
    eachindex(IndexStyle(A,B...), A, B...)
2✔
387
end
388
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
12,516,856✔
389
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
2,147,483,647✔
390
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
1✔
391
    @inline
607✔
392
    indsA = eachindex(IndexLinear(), A)
607✔
393
    _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
1,216✔
394
        throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
395
    indsA
606✔
396
end
397
function _all_match_first(f::F, inds, A, B...) where F<:Function
398
    @inline
616✔
399
    (inds == f(A)) & _all_match_first(f, inds, B...)
623✔
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)))
5,289✔
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)))
27,561,835✔
450
firstindex(a, d) = (@inline; first(axes(a, d)))
1,845✔
451

452
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
492,535✔
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,101✔
472
    x = iterate(itr)
2,163✔
473
    x === nothing && throw(ArgumentError("collection must be non-empty"))
1,132✔
474
    x[1]
1,130✔
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)
11✔
505
    n < 0 && throw(ArgumentError("Number of elements must be non-negative"))
26✔
506
    v[range(begin, length=min(n, checked_length(v)))]
36✔
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]
324,781,742✔
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)
8✔
555
    n < 0 && throw(ArgumentError("Number of elements must be non-negative"))
53✔
556
    v[range(stop=lastindex(v), length=min(n, checked_length(v)))]
93✔
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,466,172✔
607
size_to_strides(s, d) = (s,)
24,396,619✔
608
size_to_strides(s) = ()
1✔
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...)
1,301✔
680
    @inline
362,079,465✔
681
    checkbounds_indices(Bool, axes(A), I)
377,552,169✔
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)
729✔
688
    @inline
899,433,805✔
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...)
1,392✔
698
    @inline
1,257,204,840✔
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})
2,110✔
724
    @inline
24,409,817✔
725
    return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
891,539,606✔
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))
577,969✔
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,584,417✔
753
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
3,067,668✔
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) =
354,540,065✔
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
9,333✔
765
    b = true
9,333✔
766
    for i in I
24,871✔
767
        b &= checkindex(Bool, inds, i)
6,328,176✔
768
    end
6,337,277✔
769
    b
22,523✔
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,292✔
821
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
10,587✔
822
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
98,152,305✔
823
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
3,219✔
824
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
16,481,629✔
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))
265,269✔
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)
16,430,283✔
834

835
to_shape(::Tuple{}) = ()
32✔
836
to_shape(dims::Dims) = dims
5,350✔
837
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
11,932,758✔
838
# each dimension
839
to_shape(i::Int) = i
111✔
840
to_shape(i::Integer) = Int(i)
173✔
841
to_shape(r::OneTo) = Int(last(r))
7,637,181✔
842
to_shape(r::AbstractUnitRange) = r
361✔
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)
23✔
867
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
1,019,804,597✔
868
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
1,019,805,196✔
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)
428✔
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}()
237✔
891
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
62✔
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)
21,757,999✔
916
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
97✔
917
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
918
    if length(dst) != length(src)
21,758,092✔
919
        resize!(dst, length(src))
21,546,191✔
920
    end
921
    copyto!(dst, src)
21,758,187✔
922
end
923

924
function copy!(dst::AbstractArray, src::AbstractArray)
925
    axes(dst) == axes(src) || throw(ArgumentError(
4✔
926
        "arrays must have the same axes for copy! (consider using `copyto!`)"))
927
    copyto!(dst, src)
4✔
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)
11,459,777✔
937
    destiter = eachindex(dest)
11,474,200✔
938
    y = iterate(destiter)
11,474,210✔
939
    for x in src
15,325,104✔
940
        y === nothing &&
5,591,540✔
941
            throw(ArgumentError("destination has fewer elements than required"))
942
        dest[y[1]] = x
5,591,539✔
943
        y = iterate(destiter, y[2])
9,198,680✔
944
    end
9,072,903✔
945
    return dest
11,474,198✔
946
end
947

948
function copyto!(dest::AbstractArray, dstart::Integer, src)
256✔
949
    i = Int(dstart)
279✔
950
    if haslength(src) && length(dest) > 0
279✔
951
        @boundscheck checkbounds(dest, i:(i + length(src) - 1))
274✔
952
        for x in src
287✔
953
            @inbounds dest[i] = x
2,350✔
954
            i += 1
2,350✔
955
        end
2,829✔
956
    else
957
        for x in src
6✔
958
            dest[i] = x
6✔
959
            i += 1
3✔
960
        end
3✔
961
    end
962
    return dest
275✔
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
10✔
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)
591,258✔
996
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
591,258✔
997
        ", elements, but n should be non-negative")))
998
    n == 0 && return dest
591,257✔
999
    dmax = dstart + n - 1
591,252✔
1000
    inds = LinearIndices(dest)
591,252✔
1001
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
1,182,502✔
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)
591,248✔
1007
    for j = 1:(sstart-1)
644,671✔
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)
591,247✔
1016
    while i <= dmax && y !== nothing
11,066,935✔
1017
        val, st = y
9,024,117✔
1018
        @inbounds dest[i] = val
10,475,688✔
1019
        y = iterate(src, st)
10,966,637✔
1020
        i += 1
10,475,688✔
1021
    end
10,475,688✔
1022
    i <= dmax && throw(BoundsError(dest, i))
591,247✔
1023
    return dest
591,246✔
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,776,056✔
1060
    isempty(src) && return dest
3,026,548✔
1061
    if dest isa BitArray
2,886,851✔
1062
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
UNCOV
1063
        return _copyto_bitarray!(dest, src)
×
1064
    end
1065
    src′ = unalias(dest, src)
3,010,213✔
1066
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
3,013,683✔
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)
163,864✔
1076
    isempty(src) && return dest
3,006,485✔
1077
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
3,006,486✔
1078
    idf, isf = first(destinds), first(srcinds)
2,879,747✔
1079
    Δi = idf - isf
2,879,747✔
1080
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
3,006,492✔
1081
        throw(BoundsError(dest, srcinds))
1082
    if deststyle isa IndexLinear
2,879,740✔
1083
        if srcstyle isa IndexLinear
2,876,608✔
1084
            # Single-index implementation
1085
            @inbounds for i in srcinds
2,791,042✔
1086
                dest[i + Δi] = src[i]
51,443,770✔
1087
            end
100,096,501✔
1088
        else
1089
            # Dual-index implementation
1090
            i = idf - 1
109,530✔
1091
            @inbounds for a in src
424,524✔
1092
                dest[i+=1] = a
2,973,652✔
1093
            end
5,727,803✔
1094
        end
1095
    else
1096
        iterdest, itersrc = eachindex(dest), eachindex(src)
3,132✔
1097
        if iterdest == itersrc
3,133✔
1098
            # Shared-iterator implementation
1099
            for I in iterdest
288✔
1100
                @inbounds dest[I] = src[I]
6,011,534✔
1101
            end
12,012,568✔
1102
        else
1103
            # Dual-iterator implementation
1104
            ret = iterate(iterdest)
5,948✔
1105
            @inbounds for a in src
5,052✔
1106
                idx, state = ret::NTuple{2,Any}
2,033,839✔
1107
                dest[idx] = a
2,033,845✔
1108
                ret = iterate(iterdest, state)
2,036,776✔
1109
            end
4,032,163✔
1110
        end
1111
    end
1112
    return dest
3,006,470✔
1113
end
1114

1115
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
72✔
1116
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
22,213✔
1117
end
1118

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

1125
function copyto!(dest::AbstractArray, dstart::Integer,
898,308✔
1126
                 src::AbstractArray, sstart::Integer,
1127
                 n::Integer)
1128
    n == 0 && return dest
898,308✔
1129
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
898,306✔
1130
        n," elements, but n should be non-negative")))
1131
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
898,305✔
1132
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
898,317✔
1133
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
898,296✔
1134
    src′ = unalias(dest, src)
898,290✔
1135
    @inbounds for i = 0:n-1
898,367✔
1136
        dest[dstart+i] = src′[sstart+i]
46,176,292✔
1137
    end
91,454,294✔
1138
    return dest
898,290✔
1139
end
1140

1141
function copy(a::AbstractArray)
107✔
1142
    @_propagate_inbounds_meta
450✔
1143
    copymutable(a)
6,592✔
1144
end
1145

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

1171
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
153,961✔
1172

1173
function copyto_axcheck!(dest, src)
114,751✔
1174
    _checkaxs(axes(dest), axes(src))
153,876✔
1175
    copyto!(dest, src)
168,057✔
1176
end
1177

1178
"""
1179
    copymutable(a)
1180

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

1186
# Examples
1187
```jldoctest
1188
julia> tup = (1, 2, 3)
1189
(1, 2, 3)
1190

1191
julia> Base.copymutable(tup)
1192
3-element Vector{Int64}:
1193
 1
1194
 2
1195
 3
1196
```
1197
"""
1198
function copymutable(a::AbstractArray)
20✔
1199
    @_propagate_inbounds_meta
2,498✔
1200
    copyto!(similar(a), a)
21,520✔
1201
end
1202
copymutable(itr) = collect(itr)
1✔
1203

1204
zero(x::AbstractArray{T}) where {T<:Number} = fill!(similar(x, typeof(zero(T))), zero(T))
3,778✔
1205
zero(x::AbstractArray{S}) where {S<:Union{Missing, Number}} = fill!(similar(x, typeof(zero(S))), zero(S))
3✔
1206
zero(x::AbstractArray) = map(zero, x)
11✔
1207

1208
function _one(unit::T, mat::AbstractMatrix) where {T}
164✔
1209
    (rows, cols) = axes(mat)
164✔
1210
    (length(rows) == length(cols)) ||
164✔
1211
      throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
1212
    zer = zero(unit)::T
164✔
1213
    require_one_based_indexing(mat)
164✔
1214
    I = similar(mat, T)
328✔
1215
    fill!(I, zer)
3,792✔
1216
    for i ∈ rows
164✔
1217
        I[i, i] = unit
661✔
1218
    end
1,158✔
1219
    I
164✔
1220
end
1221

1222
one(x::AbstractMatrix{T}) where {T} = _one(one(T), x)
139✔
1223
oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
31✔
1224

1225
## iteration support for arrays by iterating over `eachindex` in the array ##
1226
# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1227

1228
# While the definitions for IndexLinear are all simple enough to inline on their
1229
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1230
# inlining.
1231
function iterate(A::AbstractArray, state=(eachindex(A),))
2,254✔
1232
    y = iterate(state...)
163,547,413✔
1233
    y === nothing && return nothing
129,133,488✔
1234
    A[y[1]], (state[1], tail(y)...)
128,650,912✔
1235
end
1236

1237
isempty(a::AbstractArray) = (length(a) == 0)
2,147,483,647✔
1238

1239

1240
## range conversions ##
1241

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

1249
## unsafe/pointer conversions ##
1250

1251
# note: the following type definitions don't mean any AbstractArray is convertible to
1252
# a data Ref. they just map the array element type to the pointer type for
1253
# convenience in cases that work.
1254
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
55,133,388✔
1255
function pointer(x::AbstractArray{T}, i::Integer) where T
101,870✔
1256
    @inline
414,438✔
1257
    pointer(x) + Int(_memory_offset(x, i))::Int
3,261,462✔
1258
end
1259

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

1267
## Special constprop heuristics for getindex/setindex
1268
typename(typeof(function getindex end)).constprop_heuristic = Core.ARRAY_INDEX_HEURISTIC
1269
typename(typeof(function setindex! end)).constprop_heuristic = Core.ARRAY_INDEX_HEURISTIC
1270

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

1283
Return a subset of array `A` as selected by the indices `inds`.
1284

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

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

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

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

1302
julia> getindex(A, 1)
1303
1
1304

1305
julia> getindex(A, [2, 1])
1306
2-element Vector{Int64}:
1307
 3
1308
 1
1309

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

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

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

1322
julia> getindex(A, :, 2)
1323
2-element Vector{Int64}:
1324
 2
1325
 4
1326

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

1332
julia> getindex(A, A .> 2)
1333
2-element Vector{Int64}:
1334
 3
1335
 4
1336
```
1337
"""
1338
function getindex(A::AbstractArray, I...)
494,954✔
1339
    @_propagate_inbounds_meta
104,936,098✔
1340
    error_if_canonical_getindex(IndexStyle(A), A, I...)
104,936,098✔
1341
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
211,238,437✔
1342
end
1343
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1344
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
141,986,306✔
1345

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

1348
struct CanonicalIndexError <: Exception
1349
    func::String
1350
    type::Any
1351
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
19✔
1352
end
1353

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

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

1364
## IndexLinear Scalar indexing: canonical method is one Int
1365
_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)
45,770,229✔
1366
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
51✔
1367
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
342✔
1368
    @inline
2,030,325✔
1369
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
43,124,768✔
1370
    @inbounds r = getindex(A, _to_linear_index(A, I...))
43,124,705✔
1371
    r
2,030,277✔
1372
end
1373
_to_linear_index(A::AbstractArray, i::Integer) = i
52,130✔
1374
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
79,161,078✔
1375
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
329,282✔
1376
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
261,593,666✔
1377

1378
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1379
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
1380
    @inline
423,620✔
1381
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
423,693✔
1382
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
426,724✔
1383
    r
423,545✔
1384
end
1385
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
1386
    @_propagate_inbounds_meta
101,338,791✔
1387
    getindex(A, I...)
121,459,088✔
1388
end
1389
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
440,027✔
1390
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1391
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1392
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
418✔
1393
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1394
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1395
    @inline
80,563✔
1396
    J, Jrem = IteratorsMD.split(I, Val(N))
80,563✔
1397
    _to_subscript_indices(A, J, Jrem)
80,563✔
1398
end
1399
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1400
    __to_subscript_indices(A, axes(A), J, Jrem)
1401
function __to_subscript_indices(A::AbstractArray,
1402
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1403
    @inline
2✔
1404
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1405
end
1406
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
80,561✔
1407
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
30,862✔
1408
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1409
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1410
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1411
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
440,027✔
1412

1413
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1414
# function that allows dispatch on array storage
1415

1416
"""
1417
    setindex!(A, X, inds...)
1418
    A[inds...] = X
1419

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

1423
$(_DOCS_ALIASING_WARNING)
1424

1425
# Examples
1426
```jldoctest
1427
julia> A = zeros(2,2);
1428

1429
julia> setindex!(A, [10, 20], [1, 2]);
1430

1431
julia> A[[3, 4]] = [30, 40];
1432

1433
julia> A
1434
2×2 Matrix{Float64}:
1435
 10.0  30.0
1436
 20.0  40.0
1437
```
1438
"""
1439
function setindex!(A::AbstractArray, v, I...)
1,028✔
1440
    @_propagate_inbounds_meta
2,546,880✔
1441
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,546,880✔
1442
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
8,117,261✔
1443
end
1444
function unsafe_setindex!(A::AbstractArray, v, I...)
1445
    @inline
732✔
1446
    @inbounds r = setindex!(A, v, I...)
732✔
1447
    r
730✔
1448
end
1449

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

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

1460
## IndexLinear Scalar indexing
1461
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
5,404,661✔
1462
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
696✔
1463
    @inline
154,359✔
1464
    @boundscheck checkbounds(A, I...)
258,842✔
1465
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
258,825✔
1466
    r
154,344✔
1467
end
1468

1469
# IndexCartesian Scalar indexing
1470
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
1471
    @_propagate_inbounds_meta
2,197,900✔
1472
    setindex!(A, v, I...)
2,197,913✔
1473
end
1474
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
1475
    @inline
23,487✔
1476
    @boundscheck checkbounds(A, I...)
23,492✔
1477
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
23,482✔
1478
    r
23,482✔
1479
end
1480

1481
_unsetindex!(A::AbstractArray, i::Integer) = _unsetindex!(A, to_index(i))
×
1482

1483
"""
1484
    parent(A)
1485

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

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

1498
julia> V = view(A, 1:2, :)
1499
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1500
 1  2
1501
 3  4
1502

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

1511
parent(a::AbstractArray) = a
2,334✔
1512

1513
## rudimentary aliasing detection ##
1514
"""
1515
    Base.unalias(dest, A)
1516

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

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

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

1527
See also [`Base.mightalias`](@ref).
1528
"""
1529
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
6,698,109✔
1530
unalias(dest, A::AbstractRange) = A
25,995,885✔
1531
unalias(dest, A) = A
3,158,091✔
1532

1533
"""
1534
    Base.unaliascopy(A)
1535

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

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

1558
"""
1559
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1560

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

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

1569
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1570
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1571
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1572
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1573
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
6,478,869✔
1574
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
44,738✔
1575
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1576
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
2,380✔
1577
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
64,455✔
1578

1579
"""
1580
    Base.dataids(A::AbstractArray)
1581

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

1584
Custom arrays that would like to opt-in to aliasing detection of their component
1585
parts can specialize this method to return the concatenation of the `dataids` of
1586
their component parts.  A typical definition for an array that wraps a parent is
1587
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1588
"""
1589
dataids(A::AbstractArray) = (UInt(objectid(A)),)
403,392✔
1590
dataids(A::Memory) = (B = ccall(:jl_genericmemory_owner, Any, (Any,), A); (UInt(pointer(B isa typeof(A) ? B : A)),))
12,670,715✔
1591
dataids(A::Array) = dataids(A.ref.mem)
9,013,052✔
1592
dataids(::AbstractRange) = ()
2,842,067✔
1593
dataids(x) = ()
18,989✔
1594

1595
## get (getindex with a default value) ##
1596

1597
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1598
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1599

1600
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
373✔
1601
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
8✔
1602
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
15✔
1603
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
4✔
1604
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
7✔
1605
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
9✔
1606

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

1625
get(A::AbstractArray, I::AbstractRange, default) = get!(similar(A, typeof(default), index_shape(I)), A, I, default)
1✔
1626

1627
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
2✔
1628
    fill!(X, default)
72✔
1629
    dst, src = indcopy(size(A), I)
2✔
1630
    X[dst...] = A[src...]
2✔
1631
    X
2✔
1632
end
1633

1634
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1635
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1636

1637
## structured matrix methods ##
1638
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
23,943✔
1639
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
32,563✔
1640

1641
## Concatenation ##
1642
eltypeof(x) = typeof(x)
1,133✔
1643
eltypeof(x::AbstractArray) = eltype(x)
1,948✔
1644

1645
promote_eltypeof() = error()
×
1646
promote_eltypeof(v1) = eltypeof(v1)
×
1647
promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2))
1,320✔
1648
promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...))
530✔
1649
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
105✔
1650
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
20✔
1651

1652
promote_eltype() = error()
×
1653
promote_eltype(v1) = eltype(v1)
×
1654
promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2))
1,523✔
1655
promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...))
515✔
1656
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
178✔
1657
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
1,540✔
1658

1659
#TODO: ERROR CHECK
1660
_cat(catdim::Int) = Vector{Any}()
1✔
1661

1662
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1663
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1664

1665
## cat: special cases
1666
vcat(X::T...) where {T}         = T[ X[i] for i=eachindex(X) ]
325✔
1667
vcat(X::T...) where {T<:Number} = T[ X[i] for i=eachindex(X) ]
233✔
1668
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=eachindex(X) ]
43✔
1669
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=eachindex(X) ]
8,000,481✔
1670

1671
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
1✔
1672
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
2✔
1673
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
10✔
1674
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
59✔
1675

1676
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
3✔
1677
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
5✔
1678

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

1684
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
1,497,722✔
1685
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
1,544,640✔
1686
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1687

1688
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
790,558✔
1689
    pos = 1
795,376✔
1690
    for k=1:Int(length(V))::Int
795,376✔
1691
        Vk = V[k]
795,615✔
1692
        p1 = pos + Int(length(Vk))::Int - 1
795,642✔
1693
        a[pos:p1] = Vk
5,789,448✔
1694
        pos = p1+1
795,615✔
1695
    end
795,854✔
1696
    a
795,376✔
1697
end
1698

1699
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
1,035✔
1700

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

1708

1709
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
299✔
1710
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
271✔
1711

1712
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1,039✔
1713
    nargs = length(A)
1,041✔
1714
    nrows = size(A[1], 1)
1,041✔
1715
    ncols = 0
1,041✔
1716
    dense = true
1,041✔
1717
    for j = 1:nargs
1,041✔
1718
        Aj = A[j]
2,144✔
1719
        if size(Aj, 1) != nrows
2,933✔
1720
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1721
        end
1722
        dense &= isa(Aj,Array)
2,143✔
1723
        nd = ndims(Aj)
2,931✔
1724
        ncols += (nd==2 ? size(Aj,2) : 1)
2,624✔
1725
    end
3,246✔
1726
    B = similar(A[1], T, nrows, ncols)
1,626✔
1727
    pos = 1
1,040✔
1728
    if dense
1,040✔
1729
        for k=1:nargs
405✔
1730
            Ak = A[k]
833✔
1731
            n = length(Ak)
1,056✔
1732
            copyto!(B, pos, Ak, 1, n)
1,411✔
1733
            pos += n
833✔
1734
        end
1,261✔
1735
    else
1736
        for k=1:nargs
635✔
1737
            Ak = A[k]
1,309✔
1738
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
1,582✔
1739
            B[:, pos:p1] = Ak
1,711✔
1740
            pos = p1+1
1,309✔
1741
        end
1,847✔
1742
    end
1743
    return B
1,040✔
1744
end
1745

1746
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
67✔
1747
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
201✔
1748

1749
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
483✔
1750
    nargs = length(A)
495✔
1751
    nrows = sum(a->size(a, 1), A)::Int
1,617✔
1752
    ncols = size(A[1], 2)
495✔
1753
    for j = 2:nargs
495✔
1754
        if size(A[j], 2) != ncols
598✔
1755
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1756
        end
1757
    end
672✔
1758
    B = similar(A[1], T, nrows, ncols)
887✔
1759
    pos = 1
494✔
1760
    for k=1:nargs
494✔
1761
        Ak = A[k]
1,071✔
1762
        p1 = pos+size(Ak,1)::Int-1
1,254✔
1763
        B[pos:p1, :] = Ak
1,127✔
1764
        pos = p1+1
1,071✔
1765
    end
1,648✔
1766
    return B
494✔
1767
end
1768

1769
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
1,545,129✔
1770

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

1774
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1775
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1776

1777
## cat: general case
1778

1779
# helper functions
1780
cat_size(A) = (1,)
2,282✔
1781
cat_size(A::AbstractArray) = size(A)
3,650✔
1782
cat_size(A, d) = 1
×
1783
cat_size(A::AbstractArray, d) = size(A, d)
16,973✔
1784

1785
cat_length(::Any) = 1
×
1786
cat_length(a::AbstractArray) = length(a)
465✔
1787

1788
cat_ndims(a) = 0
×
1789
cat_ndims(a::AbstractArray) = ndims(a)
674✔
1790

1791
cat_indices(A, d) = OneTo(1)
2,283✔
1792
cat_indices(A::AbstractArray, d) = axes(A, d)
5,173✔
1793

1794
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
819✔
1795
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1796
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,659✔
1797
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1798
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
770✔
UNCOV
1799
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
×
1800

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

1816
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1817
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1818
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
503✔
1819
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
477✔
1820
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1821
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
2,281✔
1822
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1823
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
1824
    _cs(ndim, shape[1], 1)
11✔
1825
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
7✔
1826
end
1827
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
1828
    next = _cs(ndim, shape[1], nshape[1])
148✔
1829
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
148✔
1830
end
1831
@inline function _cshp(ndim::Int, dims, shape, nshape)
86✔
1832
    a = shape[1]
4,358✔
1833
    b = nshape[1]
4,358✔
1834
    next = dims[1] ? a + b : _cs(ndim, a, b)
4,816✔
1835
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
4,428✔
1836
end
1837

1838
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,002✔
1839
    "mismatch in dimension $d (expected $a got $b)")))
1840

1841
dims2cat(::Val{dims}) where dims = dims2cat(dims)
528✔
1842
function dims2cat(dims)
5✔
1843
    if any(≤(0), dims)
2,915✔
1844
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1845
    end
1846
    ntuple(in(dims), maximum(dims))
2,131✔
1847
end
1848

1849
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
1,386✔
1850

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

1864
# Why isn't this called `__cat!`?
1865
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
2,987✔
1866

1867
function __cat_offset!(A, shape, catdims, offsets, x, X...)
3,106✔
1868
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1869
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
37,513✔
1870
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
6,042✔
1871
end
1872
__cat_offset!(A, shape, catdims, offsets) = A
2,374✔
1873

1874
function __cat_offset1!(A, shape, catdims, offsets, x)
6✔
1875
    inds = ntuple(length(offsets)) do i
6,196✔
1876
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
9,528✔
1877
    end
1878
    _copy_or_fill!(A, inds, x)
70,569✔
1879
    newoffsets = ntuple(length(offsets)) do i
6,004✔
1880
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
8,277✔
1881
    end
1882
    return newoffsets
6,002✔
1883
end
1884

1885
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
3,199✔
1886
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
67,334✔
1887

1888
"""
1889
    vcat(A...)
1890

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

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

1897
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1898

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

1908
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1909
true
1910

1911
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1912
true
1913

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

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

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

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

1932
julia> vs = [[1, 2], [3, 4], [5, 6]];
1933

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

1943
julia> ans == collect(Iterators.flatten(vs))
1944
true
1945
```
1946
"""
1947
vcat(X...) = cat(X...; dims=Val(1))
469✔
1948
"""
1949
    hcat(A...)
1950

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

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

1958
See also [`vcat`](@ref), [`hvcat`](@ref).
1959

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

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

1971
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1972
true
1973

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

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

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

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

1988
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
1989
0×3 Matrix{Int64}
1990

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

1999
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
393✔
2000
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
324✔
2001

2002
"""
2003
    cat(A...; dims)
2004

2005
Concatenate the input arrays along the dimensions specified in `dims`.
2006

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

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

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

2021
The keyword also accepts `Val(dims)`.
2022

2023
!!! compat "Julia 1.8"
2024
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
2025

2026
# Examples
2027

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

2034
julia> b = [4 5 6]
2035
1×3 Matrix{Int64}:
2036
 4  5  6
2037

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

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

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

2053
# Extended Help
2054

2055
Concatenate 3D arrays:
2056
```jldoctest
2057
julia> a = ones(2, 2, 3);
2058

2059
julia> b = ones(2, 2, 4);
2060

2061
julia> c = cat(a, b; dims=3);
2062

2063
julia> size(c) == (2, 2, 7)
2064
true
2065
```
2066

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

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

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

2092
!!! note
2093
    `cat` does not join two strings, you may want to use `*`.
2094

2095
```jldoctest
2096
julia> a = "aaa";
2097

2098
julia> b = "bbb";
2099

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

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

2109
julia> a * b
2110
"aaabbb"
2111
```
2112
"""
2113
@inline cat(A...; dims) = _cat(dims, A...)
3,752✔
2114
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
2115
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
216✔
2116

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

2128
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
2129
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2130
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
2131
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2132
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
2133
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
2134

2135
# 2d horizontal and vertical concatenation
2136

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

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

2150
"""
2151
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2152

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

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

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

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

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

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

2191
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T
578✔
2192
    nbr = length(rows)  # number of block rows
578✔
2193

2194
    nc = 0
578✔
2195
    for i=1:rows[1]
578✔
2196
        nc += size(as[i],2)
1,089✔
2197
    end
1,600✔
2198

2199
    nr = 0
578✔
2200
    a = 1
578✔
2201
    for i = 1:nbr
578✔
2202
        nr += size(as[a],1)
819✔
2203
        a += rows[i]
819✔
2204
    end
1,060✔
2205

2206
    out = similar(as[1], T, nr, nc)
620✔
2207

2208
    a = 1
578✔
2209
    r = 1
578✔
2210
    for i = 1:nbr
578✔
2211
        c = 1
819✔
2212
        szi = size(as[a],1)
819✔
2213
        for j = 1:rows[i]
819✔
2214
            Aj = as[a+j-1]
1,415✔
2215
            szj = size(Aj,2)
1,415✔
2216
            if size(Aj,1) != szi
1,415✔
2217
                throw(DimensionMismatch("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
1✔
2218
            end
2219
            if c-1+szj > nc
2,711✔
2220
                throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
1✔
2221
            end
2222
            out[r:r-1+szi, c:c-1+szj] = Aj
1,413✔
2223
            c += szj
1,413✔
2224
        end
2,009✔
2225
        if c != nc+1
817✔
2226
            throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
1✔
2227
        end
2228
        r += szi
816✔
2229
        a += rows[i]
816✔
2230
    end
1,057✔
2231
    out
575✔
2232
end
2233

2234
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2235
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2236

2237
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,285✔
2238
    nr = length(rows)
1,285✔
2239
    nc = rows[1]
1,285✔
2240

2241
    a = Matrix{T}(undef, nr, nc)
2,570✔
2242
    if length(a) != length(xs)
1,285✔
2243
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2244
    end
2245
    k = 1
1,283✔
2246
    @inbounds for i=1:nr
1,283✔
2247
        if nc != rows[i]
3,493✔
2248
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2249
        end
2250
        for j=1:nc
3,492✔
2251
            a[i,j] = xs[k]
9,624✔
2252
            k += 1
9,624✔
2253
        end
15,756✔
2254
    end
5,702✔
2255
    a
1,282✔
2256
end
2257

2258
function hvcat_fill!(a::Array, xs::Tuple)
483✔
2259
    nr, nc = size(a,1), size(a,2)
492✔
2260
    len = length(xs)
492✔
2261
    if nr*nc != len
492✔
2262
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2263
    end
2264
    k = 1
491✔
2265
    for i=1:nr
491✔
2266
        @inbounds for j=1:nc
1,313✔
2267
            a[i,j] = xs[k]
8,757✔
2268
            k += 1
8,757✔
2269
        end
16,201✔
2270
    end
2,135✔
2271
    a
491✔
2272
end
2273

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

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

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

2301
## N-dimensional concatenation ##
2302

2303
"""
2304
    hvncat(dim::Int, row_first, values...)
2305
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2306
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2307

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

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

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

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

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

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

2340
[:, :, 2] =
2341
 3
2342
 4
2343

2344
[:, :, 3] =
2345
 5
2346
 6
2347

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

2353
[:, :, 2] =
2354
 3  4
2355

2356
[:, :, 3] =
2357
 5  6
2358

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

2364
[:, :, 2] =
2365
 4  5  6
2366
```
2367

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

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

2391
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
28✔
2392
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
91✔
2393
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
89✔
2394
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2395
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2396
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
129✔
2397

2398

2399
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2400
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2401

2402
# 1-dimensional hvncat methods
2403

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

2412
_typed_hvncat_0d_only_one() =
8✔
2413
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2414

2415
# `@constprop :aggressive` here to form constant `Val(dim)` type to get type stability
2416
@constprop :aggressive _typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters
77✔
2417

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

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

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

2445
    nd = N
16✔
2446

2447
    Ndim = 0
16✔
2448
    for i ∈ eachindex(as)
16✔
2449
        Ndim += cat_size(as[i], N)
36✔
2450
        nd = max(nd, cat_ndims(as[i]))
36✔
2451
        for d ∈ 1:N - 1
30✔
2452
            cat_size(as[1], d) == cat_size(as[i], d) || throw(DimensionMismatch("mismatched size along axis $d in element $i"))
35✔
2453
        end
38✔
2454
    end
40✔
2455

2456
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
29✔
2457
    k = 1
12✔
2458
    for a ∈ as
12✔
2459
        for i ∈ eachindex(a)
24✔
2460
            A[k] = a[i]
24✔
2461
            k += 1
24✔
2462
        end
29✔
2463
    end
31✔
2464
    return A
12✔
2465
end
2466

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

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

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

2499
# 0-dimensional cases for balanced and unbalanced hvncat method
2500

2501
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2502
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2503

2504

2505
# balanced dimensions hvncat methods
2506

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

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

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

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

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

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

2577
    d1 = row_first ? 2 : 1
57✔
2578
    d2 = row_first ? 1 : 2
57✔
2579

2580
    outdims = zeros(Int, N)
200✔
2581

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

2603
    # discover number of rows or columns
2604
    for i ∈ 1:dims[d1]
51✔
2605
        outdims[d1] += cat_size(as[i], d1)
106✔
2606
    end
161✔
2607

2608
    currentdims = zeros(Int, N)
173✔
2609
    blockcount = 0
51✔
2610
    elementcount = 0
51✔
2611
    for i ∈ eachindex(as)
51✔
2612
        elementcount += cat_length(as[i])
302✔
2613
        currentdims[d1] += cat_size(as[i], d1)
255✔
2614
        if currentdims[d1] == outdims[d1]
255✔
2615
            currentdims[d1] = 0
127✔
2616
            for d ∈ (d2, 3:N...)
127✔
2617
                currentdims[d] += cat_size(as[i], d)
199✔
2618
                if outdims[d] == 0 # unfixed dimension
199✔
2619
                    blockcount += 1
164✔
2620
                    if blockcount == dims[d]
164✔
2621
                        outdims[d] = currentdims[d]
86✔
2622
                        currentdims[d] = 0
86✔
2623
                        blockcount = 0
86✔
2624
                    else
2625
                        break
78✔
2626
                    end
2627
                else # fixed dimension
2628
                    if currentdims[d] == outdims[d] # end of dimension
35✔
2629
                        currentdims[d] = 0
22✔
2630
                    elseif currentdims[d] < outdims[d] # dimension in progress
13✔
2631
                        break
13✔
2632
                    else # exceeded dimension
2633
                        throw(DimensionMismatch("argument $i has too many elements along axis $d"))
×
2634
                    end
2635
                end
2636
            end
138✔
2637
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
128✔
2638
            throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
16✔
2639
        end
2640
    end
443✔
2641

2642
    outlen = prod(outdims)
70✔
2643
    elementcount == outlen ||
35✔
2644
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2645

2646
    # copy into final array
2647
    A = cat_similar(as[1], T, outdims)
35✔
2648
    # @assert all(==(0), currentdims)
2649
    outdims .= 0
105✔
2650
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
35✔
2651
    return A
35✔
2652
end
2653

2654

2655
# unbalanced dimensions hvncat methods
2656

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

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

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

2675
    d1 = row_first ? 2 : 1
66✔
2676
    d2 = row_first ? 1 : 2
66✔
2677

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

2693
    elementcount = 0
63✔
2694
    for i ∈ eachindex(as)
63✔
2695
        elementcount += cat_length(as[i])
351✔
2696
        wasstartblock = false
310✔
2697
        for d ∈ 1:N
310✔
2698
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
898✔
2699
            dsize = cat_size(as[i], ad)
1,374✔
2700
            blockcounts[d] += 1
898✔
2701

2702
            if d == 1 || i == 1 || wasstartblock
1,486✔
2703
                currentdims[d] += dsize
616✔
2704
            elseif dsize != cat_size(as[i - 1], ad)
420✔
2705
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
8✔
2706
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2707
            end
2708

2709
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
890✔
2710

2711
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
890✔
2712
            if isendblock
890✔
2713
                if outdims[d] == -1
264✔
2714
                    outdims[d] = currentdims[d]
135✔
2715
                elseif outdims[d] != currentdims[d]
129✔
2716
                    throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
40✔
2717
                                             expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2718
                end
2719
                currentdims[d] = 0
224✔
2720
                blockcounts[d] = 0
224✔
2721
                shapepos[d] += 1
224✔
2722
                d > 1 && (blockcounts[d - 1] == 0 ||
225✔
2723
                    throw(DimensionMismatch("shape in level $d is inconsistent; level counts must nest \
2724
                                             evenly into each other")))
2725
            end
2726
        end
1,437✔
2727
    end
508✔
2728

2729
    outlen = prod(outdims)
28✔
2730
    elementcount == outlen ||
14✔
2731
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2732

2733
    if row_first
14✔
2734
        outdims[1], outdims[2] = outdims[2], outdims[1]
10✔
2735
    end
2736

2737
    # @assert all(==(0), currentdims)
2738
    # @assert all(==(0), blockcounts)
2739

2740
    # copy into final array
2741
    A = cat_similar(as[1], T, outdims)
14✔
2742
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
14✔
2743
    return A
14✔
2744
end
2745

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

2764
                @inbounds for j ∈ 1:N
1,848✔
2765
                    inneroffsets[j] += 1
4,097✔
2766
                    inneroffsets[j] < cat_size(a, j) && break
7,908✔
2767
                    inneroffsets[j] = 0
2,468✔
2768
                end
2,468✔
2769
            end
1,848✔
2770
        else
2771
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2772
            A[Ai] = a
27✔
2773
        end
2774

2775
        @inbounds for j ∈ (d1, d2, 3:N...)
263✔
2776
            offsets[j] += cat_size(a, j)
503✔
2777
            offsets[j] < outdims[j] && break
503✔
2778
            offsets[j] = 0
294✔
2779
        end
294✔
2780
    end
263✔
2781
end
2782

2783
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
2784
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2785
    Ai = inneroffsets[1] + offsets[1] + 1
1,875✔
2786
    for j ∈ 2:nd
1,875✔
2787
        increment = inneroffsets[j] + offsets[j]
7,018✔
2788
        for k ∈ 1:j-1
7,018✔
2789
            increment *= outdims[k]
17,089✔
2790
        end
27,160✔
2791
        Ai += increment
7,018✔
2792
    end
12,161✔
2793
    Ai
1,875✔
2794
end
2795

2796
"""
2797
    stack(iter; [dims])
2798

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

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

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

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

2815
!!! compat "Julia 1.9"
2816
    This function requires at least Julia 1.9.
2817

2818
# Examples
2819
```jldoctest
2820
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2821

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

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

2830
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2831
true
2832

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

2838
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2839
true
2840

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

2847
julia> x = rand(3,4);
2848

2849
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2850
true
2851
```
2852

2853
Higher-dimensional examples:
2854

2855
```jldoctest
2856
julia> A = rand(5, 7, 11);
2857

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

2860
julia> (element = size(first(E)), container = size(E))
2861
(element = (5, 11), container = (7,))
2862

2863
julia> stack(E) |> size
2864
(5, 11, 7)
2865

2866
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2867
true
2868

2869
julia> A == stack(E; dims=2)
2870
true
2871

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

2874
julia> (element = size(first(M)), container = size(M))
2875
(element = (2, 3), container = (5, 7))
2876

2877
julia> stack(M) |> size  # keeps all dimensions
2878
(2, 3, 5, 7)
2879

2880
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2881
(35, 2, 3)
2882

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

2889
"""
2890
    stack(f, args...; [dims])
2891

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

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

2899
See also [`mapslices`](@ref), [`eachcol`](@ref).
2900

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

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

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

2921
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2922

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

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

2954
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,256✔
2955
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
471✔
2956
_iterator_axes(x, ::IteratorSize) = axes(x)
8,785✔
2957

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

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

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

2983
    newaxis = _vec_axis(A)
21✔
2984
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
122✔
2985
    B = similar(_ensure_array(x1), T, outax...)
41✔
2986

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

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

3001
    i = firstindex(B, dims)
21✔
3002
    copyto!(view(B, before..., i, after...), x1)
37✔
3003

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

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

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

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

3025

3026
## Reductions and accumulates ##
3027

3028
function isequal(A::AbstractArray, B::AbstractArray)
17,981✔
3029
    if A === B return true end
60,455✔
3030
    if axes(A) != axes(B)
117,342✔
3031
        return false
2,924✔
3032
    end
3033
    for (a, b) in zip(A, B)
114,215✔
3034
        if !isequal(a, b)
1,043,556✔
3035
            return false
744✔
3036
        end
3037
    end
2,028,828✔
3038
    return true
56,465✔
3039
end
3040

3041
function cmp(A::AbstractVector, B::AbstractVector)
41✔
3042
    for (a, b) in zip(A, B)
704✔
3043
        if !isequal(a, b)
859✔
3044
            return isless(a, b) ? -1 : 1
475✔
3045
        end
3046
    end
1,038✔
3047
    return cmp(length(A), length(B))
24✔
3048
end
3049

3050
"""
3051
    isless(A::AbstractVector, B::AbstractVector)
3052

3053
Return `true` when `A` is less than `B` in lexicographic order.
3054
"""
3055
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
452✔
3056

3057
function (==)(A::AbstractArray, B::AbstractArray)
6,478,582✔
3058
    if axes(A) != axes(B)
12,981,907✔
3059
        return false
3,971✔
3060
    end
3061
    anymissing = false
6,481,494✔
3062
    for (a, b) in zip(A, B)
12,093,000✔
3063
        eq = (a == b)
309,575,193✔
3064
        if ismissing(eq)
275,183,015✔
3065
            anymissing = true
24✔
3066
        elseif !eq
308,685,800✔
3067
            return false
2,944✔
3068
        end
3069
    end
611,764,657✔
3070
    return anymissing ? missing : true
6,486,059✔
3071
end
3072

3073
# _sub2ind and _ind2sub
3074
# fallbacks
3075
function _sub2ind(A::AbstractArray, I...)
284✔
3076
    @inline
245,666,996✔
3077
    _sub2ind(axes(A), I...)
261,593,666✔
3078
end
3079

3080
function _ind2sub(A::AbstractArray, ind)
3081
    @inline
440,028✔
3082
    _ind2sub(axes(A), ind)
440,028✔
3083
end
3084

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

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

3101
_sub2ind_recurse(::Any, L, ind) = ind
44,488✔
3102
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
360✔
3103
    @inline
1,159✔
3104
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
67,751✔
3105
end
3106
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
899✔
3107
    @inline
11,504,851✔
3108
    r1 = inds[1]
11,569,978✔
3109
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
534,790,208✔
3110
end
3111

3112
nextL(L, l::Integer) = L*l
500,752✔
3113
nextL(L, r::AbstractUnitRange) = L*length(r)
271,479,628✔
3114
nextL(L, r::Slice) = L*length(r.indices)
×
3115
offsetin(i, l::Integer) = i-1
1,547,944✔
3116
offsetin(i, r::AbstractUnitRange) = i-first(r)
533,116,571✔
3117

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

3125
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3126
function _ind2sub_recurse(indslast::NTuple{1}, ind)
3127
    @inline
440,026✔
3128
    (_lookup(ind, indslast[1]),)
440,026✔
3129
end
3130
function _ind2sub_recurse(inds, ind)
3131
    @inline
786,015✔
3132
    r1 = inds[1]
786,015✔
3133
    indnext, f, l = _div(ind, r1)
786,015✔
3134
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
786,015✔
3135
end
3136

3137
_lookup(ind, d::Integer) = ind+1
1✔
3138
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
440,025✔
3139
_div(ind, d::Integer) = div(ind, d), 1, d
1✔
3140
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
786,014✔
3141

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

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

3170
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3171
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3172
_sub2ind_vec(i) = ()
×
3173

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

3186
## iteration utilities ##
3187

3188
"""
3189
    foreach(f, c...) -> Nothing
3190

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

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

3198
# Examples
3199
```jldoctest
3200
julia> tri = 1:3:7; res = Int[];
3201

3202
julia> foreach(x -> push!(res, x^2), tri)
3203

3204
julia> res
3205
3-element Vector{$(Int)}:
3206
  1
3207
 16
3208
 49
3209

3210
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3211
1 with a
3212
4 with b
3213
7 with c
3214
```
3215
"""
3216
foreach(f, itr) = (for x in itr; f(x); end; nothing)
376,833,454✔
3217
foreach(f, itr, itrs...) = (for z in zip(itr, itrs...); f(z...); end; nothing)
1✔
3218

3219
## map over arrays ##
3220

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

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

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

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

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

3244
[:, :, 2] =
3245
 11  13  15  17  19
3246
 12  14  16  18  20
3247

3248
[:, :, 3] =
3249
 21  23  25  27  29
3250
 22  24  26  28  30
3251

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

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

3259
[:, :, 2] =
3260
 11  11  11  11
3261

3262
[:, :, 3] =
3263
 21  21  21  21
3264

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

3267
julia> B == stack(f2, eachslice(A, dims=3))
3268
true
3269

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

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

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

3285
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3286
true
3287
```
3288

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

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

3307
    # Apply the function to the first slice in order to determine the next steps
3308
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
206✔
3309
    Aslice = A[idx1...]
72✔
3310
    r1 = f(Aslice)
120✔
3311

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

3328
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3329
    din = Ref(0)
42✔
3330
    Rsize = ntuple(ndims(A)) do d
51✔
3331
        if d in dims
141✔
3332
            axes(res1, din[] += 1)
56✔
3333
        else
3334
            axes(A,d)
42✔
3335
        end
3336
    end
3337
    R = similar(res1, Rsize)
65✔
3338

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

3344
    # That skips the first element, which we already have:
3345
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
187✔
3346
    concatenate_setindex!(R, res1, ridx...)
70✔
3347

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

3355
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
59✔
3356
    return R
42✔
3357
end
3358

3359
@noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
42✔
3360
    must_extend = any(dim_mask .& size(R) .> 1)
46✔
3361
    if safe_for_reuse
42✔
3362
        # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3363
        # so we can reuse Aslice
3364
        for I in indices
66✔
3365
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
115✔
3366
            _unsafe_getindex!(Aslice, A, idx...)
115✔
3367
            r = f(Aslice)
230✔
3368
            if r isa AbstractArray || must_extend
115✔
3369
                ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
89✔
3370
                R[ridx...] = r
178✔
3371
            else
3372
                ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
26✔
3373
                R[ridx...] = r
26✔
3374
            end
3375
        end
115✔
3376
    else
3377
        # we can't guarantee safety (#18524), so allocate new storage for each slice
3378
        for I in indices
18✔
3379
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
13✔
3380
            ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
13✔
3381
            concatenate_setindex!(R, f(A[idx...]), ridx...)
26✔
3382
        end
13✔
3383
    end
3384
end
3385

3386
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
7✔
3387
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
63✔
3388

3389
## 1 argument
3390

3391
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
2,960✔
3392
    for (i,j) in zip(eachindex(dest),eachindex(A))
587,053,538✔
3393
        val = f(@inbounds A[j])
494,750,288✔
3394
        @inbounds dest[i] = val
358,525,324✔
3395
    end
442,171,085✔
3396
    return dest
312,173,975✔
3397
end
3398

3399
# map on collections
3400
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
169,539✔
3401

3402
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
3,573✔
3403
mapany(f, itr) = Any[f(x) for x in itr]
×
3404

3405
"""
3406
    map(f, c...) -> collection
3407

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

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

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

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

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

3432
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3433
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3434

3435
## 2 argument
3436
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
122✔
3437
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
376✔
3438
        @inbounds a, b = A[j], B[k]
71,137✔
3439
        val = f(a, b)
71,137✔
3440
        @inbounds dest[i] = val
71,137✔
3441
    end
142,086✔
3442
    return dest
188✔
3443
end
3444

3445
## N argument
3446

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

3453
function map_n!(f::F, dest::AbstractArray, As) where F
45✔
3454
    idxs1 = LinearIndices(As[1])
45✔
3455
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
360✔
3456
    for i = idxs1
45✔
3457
        @inbounds I = ith_all(i, As)
4,020✔
3458
        val = f(I...)
4,020✔
3459
        @inbounds dest[i] = val
4,020✔
3460
    end
7,995✔
3461
    return dest
45✔
3462
end
3463

3464
"""
3465
    map!(function, destination, collection...)
3466

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

3470
$(_DOCS_ALIASING_WARNING)
3471

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

3474
# Examples
3475
```jldoctest
3476
julia> a = zeros(3);
3477

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

3480
julia> a
3481
3-element Vector{Float64}:
3482
 2.0
3483
 4.0
3484
 6.0
3485

3486
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3487
5-element Vector{$(Int)}:
3488
 101
3489
 103
3490
 105
3491
   0
3492
   0
3493
```
3494
"""
3495
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
43✔
3496
    isempty(As) && throw(ArgumentError(
46✔
3497
        """map! requires at least one "source" argument"""))
3498
    map_n!(f, dest, As)
45✔
3499
end
3500

3501
"""
3502
    map(f, A::AbstractArray...) -> N-array
3503

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

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

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

3516
julia> map(+, [1 2; 3 4], zeros(2,1))
3517
ERROR: DimensionMismatch
3518

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

3528
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3529
# (note: must not cause a dispatch loop when 1-item case is not defined)
3530
push!(A, a, b) = push!(push!(A, a), b)
995✔
3531
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
2✔
UNCOV
3532
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3533
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
2✔
3534

3535
## hashing AbstractArray ##
3536

3537
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3538
function hash(A::AbstractArray, h::UInt)
17,061✔
3539
    h += hash_abstractarray_seed
17,061✔
3540
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3541
    # Instead hash the tuple of firsts and lasts along each dimension
3542
    h = hash(map(first, axes(A)), h)
17,298✔
3543
    h = hash(map(last, axes(A)), h)
17,298✔
3544

3545
    # For short arrays, it's not worth doing anything complicated
3546
    if length(A) < 8192
17,298✔
3547
        for x in A
22,087✔
3548
            h = hash(x, h)
2,354,473✔
3549
        end
2,237,725✔
3550
        return h
17,057✔
3551
    end
3552

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

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

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

3574
    # Start at the last index
3575
    keyidx = last(ks)
4✔
3576
    linidx = key_to_linear[keyidx]
4✔
3577
    fibskip = prevfibskip = oneunit(linidx)
4✔
3578
    first_linear = first(LinearIndices(linear_to_key))
4✔
3579
    n = 0
4✔
3580
    while true
28,192✔
3581
        n += 1
28,192✔
3582
        # Hash the element
3583
        elt = A[keyidx]
28,192✔
3584
        h = hash(keyidx=>elt, h)
28,192✔
3585

3586
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3587
        linidx = key_to_linear[keyidx]
28,192✔
3588
        linidx < fibskip + first_linear && break
28,192✔
3589
        linidx -= fibskip
28,188✔
3590
        keyidx = linear_to_key[linidx]
28,188✔
3591

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

3602
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3603
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3604
        keyidx === nothing && break
28,188✔
3605
    end
28,188✔
3606

3607
    return h
4✔
3608
end
3609

3610
# The semantics of `collect` are weird. Better to write our own
3611
function rest(a::AbstractArray{T}, state...) where {T}
5✔
3612
    v = Vector{T}(undef, 0)
11✔
3613
    # assume only very few items are taken from the front
3614
    sizehint!(v, length(a))
11✔
3615
    return foldl(push!, Iterators.rest(a, state...), init=v)
11✔
3616
end
3617

3618

3619
## keepat! ##
3620

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

3623
function _keepat!(a::AbstractVector, inds)
7✔
3624
    local prev
11✔
3625
    i = firstindex(a)
11✔
3626
    for k in inds
17✔
3627
        if @isdefined(prev)
34✔
3628
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
27✔
3629
        end
3630
        ak = a[k] # must happen even when i==k for bounds checking
35✔
3631
        if i != k
29✔
3632
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
13✔
3633
        end
3634
        prev = k
29✔
3635
        i = nextind(a, i)
29✔
3636
    end
50✔
3637
    deleteat!(a, i:lastindex(a))
11✔
3638
    return a
6✔
3639
end
3640

3641
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
4✔
3642
    length(m) == length(a) || throw(BoundsError(a, m))
7✔
3643
    j = firstindex(a)
3✔
3644
    for i in eachindex(a, m)
3✔
3645
        @inbounds begin
20✔
3646
            if m[i]
20✔
3647
                i == j || (a[j] = a[i])
15✔
3648
                j = nextind(a, j)
8✔
3649
            end
3650
        end
3651
    end
38✔
3652
    deleteat!(a, j:lastindex(a))
3✔
3653
end
3654

3655
## 1-d circshift ##
3656
function circshift!(a::AbstractVector, shift::Integer)
43✔
3657
    n = length(a)
61✔
3658
    n == 0 && return a
61✔
3659
    shift = mod(shift, n)
118✔
3660
    shift == 0 && return a
59✔
3661
    l = lastindex(a)
29✔
3662
    reverse!(a, firstindex(a), l-shift)
29✔
3663
    reverse!(a, l-shift+1, lastindex(a))
29✔
3664
    reverse!(a)
29✔
3665
    return a
29✔
3666
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