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

JuliaLang / julia / #38098

11 Jun 2025 05:14AM UTC coverage: 25.689% (+0.002%) from 25.687%
#38098

push

local

web-flow
Test: Fix failfast for for loops (#58695)

0 of 6 new or added lines in 1 file covered. (0.0%)

447 existing lines in 3 files now uncovered.

12818 of 49897 relevant lines covered (25.69%)

657987.66 hits per line

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

18.81
/base/abstractarray.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
## Basic functions ##
4

5
"""
6
    AbstractArray{T,N}
7

8
Supertype for `N`-dimensional arrays (or array-like types) with elements of type `T`.
9
[`Array`](@ref) and other types are subtypes of this. See the manual section on the
10
[`AbstractArray` interface](@ref man-interface-array).
11

12
See also: [`AbstractVector`](@ref), [`AbstractMatrix`](@ref), [`eltype`](@ref), [`ndims`](@ref).
13
"""
14
AbstractArray
15

16
convert(::Type{T}, a::T) where {T<:AbstractArray} = a
×
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
×
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
×
19

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

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

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

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

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

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

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

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

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

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

51
# Examples
52

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

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

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

63
# Usage note
64

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

69
```julia
70
ix = axes(v, 1)
71
ix[2:end]          # will work for eg Vector, but may fail in general
72
ix[(begin+1):end]  # works for generalized indexes
73
```
74
"""
75
function axes(A::AbstractArray{T,N}, d) where {T,N}
76
    @inline
52,093✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
62,251✔
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)
14,206,453✔
97
    @inline
14,261,146✔
98
    map(unchecked_oneto, size(A))
91,816,747✔
99
end
100

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

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

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

120

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

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

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

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

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

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

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

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

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

161
julia> keys([4 5; 6 7])
162
CartesianIndices((2, 2))
163
```
164
"""
165
keys(a::AbstractArray) = CartesianIndices(axes(a))
×
166
keys(a::AbstractVector) = LinearIndices(a)
1,888,127✔
167

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

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

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

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

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

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

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

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

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

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

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

215
prevind(::AbstractArray, i::Integer) = Int(i)-1
398✔
216
nextind(::AbstractArray, i::Integer) = Int(i)+1
3,270,945✔
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
305✔
240
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
×
241
eltype(x) = eltype(typeof(x))
246,122✔
242
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
231✔
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))
369,461✔
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
10,711✔
275
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N::Int
×
276
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
×
277

278
"""
279
    length(collection)::Integer
280

281
Return the number of elements in the collection.
282

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

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

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

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

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

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

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

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

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

317
# `eachindex` is mostly an optimization of `keys`
318
eachindex(itrs...) = keys(itrs...)
2✔
319

320
# eachindex iterates over all indices. IndexCartesian definitions are later.
321
eachindex(A::AbstractVector) = (@inline(); axes1(A))
12,256,367✔
322

323

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

333
"""
334
    eachindex(A...)
335
    eachindex(::IndexStyle, A::AbstractArray...)
336

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

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

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

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

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

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

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

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

382
function eachindex(A::AbstractArray, B::AbstractArray)
×
383
    @inline
×
384
    eachindex(IndexStyle(A,B), A, B)
×
385
end
386
function eachindex(A::AbstractArray, B::AbstractArray...)
×
387
    @inline
×
388
    eachindex(IndexStyle(A,B...), A, B...)
×
389
end
390
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
×
391
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
69,684,183✔
392
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
×
393
    @inline
×
394
    indsA = eachindex(IndexLinear(), A)
×
395
    indsBs = map(X -> eachindex(IndexLinear(), X), B)
×
396
    all(==(indsA), indsBs) ||
×
397
        throw_eachindex_mismatch_indices("indices", indsA, indsBs...)
398
    indsA
×
399
end
400

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

404
"""
405
    lastindex(collection)::Integer
406
    lastindex(collection, d)::Integer
407

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

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

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

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

420
julia> lastindex(rand(3,4,5), 2)
421
4
422
```
423
"""
424
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
35,572,915✔
425
lastindex(a, d) = (@inline; last(axes(a, d)))
1,147✔
426

427
"""
428
    firstindex(collection)::Integer
429
    firstindex(collection, d)::Integer
430

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

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

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

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

443
julia> firstindex(rand(3,4,5), 2)
444
1
445
```
446
"""
447
firstindex(a::AbstractArray) = (@inline; first(eachindex(IndexLinear(), a)))
14,478✔
448
firstindex(a, d) = (@inline; first(axes(a, d)))
×
449

450
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
325✔
451

452
"""
453
    first(coll)
454

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

458
See also: [`only`](@ref), [`firstindex`](@ref), [`last`](@ref).
459

460
# Examples
461
```jldoctest
462
julia> first(2:2:10)
463
2
464

465
julia> first([1; 2; 3; 4])
466
1
467
```
468
"""
469
function first(itr)
470
    x = iterate(itr)
×
471
    x === nothing && throw(ArgumentError("collection must be non-empty"))
×
472
    x[1]
×
473
end
474

475
"""
476
    first(itr, n::Integer)
477

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

481
See also: [`startswith`](@ref), [`Iterators.take`](@ref).
482

483
!!! compat "Julia 1.6"
484
    This method requires at least Julia 1.6.
485

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

493
julia> first(1:6, 10)
494
1:6
495

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

507
"""
508
    last(coll)
509

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

514
See also [`first`](@ref), [`endswith`](@ref).
515

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

521
julia> last([1; 2; 3; 4])
522
4
523
```
524
"""
525
last(a) = a[end]
2,261,819✔
526

527
"""
528
    last(itr, n::Integer)
529

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

533
!!! compat "Julia 1.6"
534
    This method requires at least Julia 1.6.
535

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

543
julia> last(1:6, 10)
544
1:6
545

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

557
"""
558
    strides(A)
559

560
Return a tuple of the memory strides in each dimension.
561

562
See also: [`stride`](@ref).
563

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

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

574
"""
575
    stride(A, k::Integer)
576

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

579
See also: [`strides`](@ref).
580

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

585
julia> stride(A,2)
586
3
587

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

604
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
×
605
size_to_strides(s, d) = (s,)
×
606
size_to_strides(s) = ()
×
607

608
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
×
609
    @boundscheck checkbounds(A, I...)
×
610
    return true
×
611
end
612

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

634
## Bounds checking ##
635

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

650
"""
651
    checkbounds(Bool, A, I...)
652

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

658
See also [`checkindex`](@ref).
659

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

664
julia> checkbounds(Bool, A, 2)
665
true
666

667
julia> checkbounds(Bool, A, 3, 4)
668
false
669

670
julia> checkbounds(Bool, A, 1:3)
671
true
672

673
julia> checkbounds(Bool, A, 1:3, 2:4)
674
false
675
```
676
"""
677
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
678
    @inline
10,706✔
679
    checkbounds_indices(Bool, axes(A), I)
125,226✔
680
end
681

682
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index;
683
# indices that do not allow linear indexing (e.g., logical arrays, cartesian indices, etc)
684
# must add specialized methods to implement their restrictions
685
function checkbounds(::Type{Bool}, A::AbstractArray, i)
6,647,844✔
686
    @inline
7,204,452✔
687
    return checkindex(Bool, eachindex(IndexLinear(), A), i)
35,622,057✔
688
end
689

690
"""
691
    checkbounds(A, I...)
692

693
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
694
"""
695
function checkbounds(A::AbstractArray, I...)
3,289,424✔
696
    @inline
3,723,206✔
697
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
7,999,202✔
698
    nothing
3,723,206✔
699
end
700

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

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

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

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

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

719
See also [`checkbounds`](@ref).
720
"""
721
function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{Any, Vararg})
722
    @inline
13,843✔
723
    return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
249,872✔
724
        checkbounds_indices(Bool, safe_tail(inds), tail(I))
725
end
726

727
checkbounds_indices(::Type{Bool}, inds::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, inds))
×
728

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

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

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

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

745
julia> checkindex(Bool, 1:20, 21)
746
false
747
```
748
"""
749
checkindex(::Type{Bool}, inds, i) = throw(ArgumentError(LazyString("unable to check bounds for indices of type ", typeof(i))))
×
750
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
1,535,182✔
751
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
×
752
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
36,195,462✔
753
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
×
754
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
×
755
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::AbstractRange) =
3,137,255✔
756
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
757
# range like indices with cheap `extrema`
758
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::LinearIndices) =
×
759
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
760

761
function checkindex(::Type{Bool}, inds, I::AbstractArray)
762
    @inline
×
763
    b = true
×
764
    for i in I
2,544✔
765
        b &= checkindex(Bool, inds, i)
28,268✔
766
    end
28,268✔
767
    b
2,544✔
768
end
769

770
# See also specializations in multidimensional
771

772
## Constructors ##
773

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

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

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

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

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

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

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

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

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

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

835
to_shape(::Tuple{}) = ()
×
836
to_shape(dims::Dims) = dims
×
837
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
552,346✔
838
# each dimension
839
to_shape(i::Int) = i
436,666✔
840
to_shape(i::Integer) = Int(i)
2,348✔
841
to_shape(r::AbstractOneTo) = _to_shape(last(r))
552,345✔
842
_to_shape(x::Integer) = to_shape(x)
439,014✔
843
_to_shape(x) = Int(x)
×
844
to_shape(r::AbstractUnitRange) = r
×
845

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

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

853
**Examples**:
854

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

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

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

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

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

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

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

881
# Examples
882

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

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

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

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

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

907
$(_DOCS_ALIASING_WARNING)
908

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

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

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

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

934
## from general iterable to any array
935

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

940
function copyto!(dest::AbstractArray, src)
38,395✔
941
    destiter = eachindex(dest)
38,395✔
942
    y = iterate(destiter)
38,395✔
943
    for x in src
65,324✔
944
        y === nothing &&
112,066✔
945
            throw(ArgumentError("destination has fewer elements than required"))
946
        dest[y[1]] = x
112,066✔
947
        y = iterate(destiter, y[2])
188,115✔
948
    end
173,926✔
949
    return dest
38,395✔
950
end
951

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

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

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

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

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

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

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

1047
$(_DOCS_ALIASING_WARNING)
1048

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

1053
julia> y = zeros(7);
1054

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

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

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

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

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

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

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

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

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

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

1179
function copyto_axcheck!(dest, src)
37✔
1180
    _checkaxs(axes(dest), axes(src))
163✔
1181
    copyto!(dest, src)
164✔
1182
end
1183

1184
"""
1185
    copymutable(a)
1186

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

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

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

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

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

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

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

1234
# While the definitions for IndexLinear are all simple enough to inline on their
1235
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1236
# inlining.
1237
iterate_starting_state(A) = iterate_starting_state(A, IndexStyle(A))
131,135✔
1238
iterate_starting_state(A, ::IndexLinear) = firstindex(A)
131,127✔
1239
iterate_starting_state(A, ::IndexStyle) = (eachindex(A),)
8✔
1240
iterate(A::AbstractArray, state = iterate_starting_state(A)) = _iterate(A, state)
265,438✔
1241
function _iterate(A::AbstractArray, state::Tuple)
1242
    y = iterate(state...)
12✔
1243
    y === nothing && return nothing
11✔
1244
    A[y[1]], (state[1], tail(y)...)
3✔
1245
end
1246
function _iterate(A::AbstractArray, state::Integer)
1247
    checkbounds(Bool, A, state) || return nothing
134,436✔
1248
    @inbounds(A[state]), state + one(state)
134,122✔
1249
end
1250

1251
isempty(a::AbstractArray) = (length(a) == 0)
61,600,337✔
1252

1253

1254
## range conversions ##
1255

UNCOV
1256
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
×
UNCOV
1257
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
×
UNCOV
1258
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
×
UNCOV
1259
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
×
UNCOV
1260
    LinRange(T(r.start), T(r.stop), length(r))
×
1261
end
1262

1263
## unsafe/pointer conversions ##
1264

1265
# note: the following type definitions don't mean any AbstractArray is convertible to
1266
# a data Ref. they just map the array element type to the pointer type for
1267
# convenience in cases that work.
1268
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
994,114✔
1269
function pointer(x::AbstractArray{T}, i::Integer) where T
1270
    @inline
20✔
1271
    pointer(x) + Int(_memory_offset(x, i))::Int
282,510✔
1272
end
1273

1274
# The distance from pointer(x) to the element at x[I...] in bytes
1275
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
282,493✔
UNCOV
1276
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
×
UNCOV
1277
    J = _to_subscript_indices(x, I...)
×
UNCOV
1278
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
×
1279
end
1280

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1346
julia> getindex(A, A .> 2)
1347
2-element Vector{Int64}:
1348
 3
1349
 4
1350
```
1351
"""
1352
function getindex(A::AbstractArray, I...)
14,682✔
1353
    @_propagate_inbounds_meta
23,305,715✔
1354
    error_if_canonical_getindex(IndexStyle(A), A, I...)
23,305,715✔
1355
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
23,485,754✔
1356
end
1357
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1358
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
765,499✔
1359

1360
@inline unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
×
1361

1362
struct CanonicalIndexError <: Exception
1363
    func::String
1364
    type::Any
UNCOV
1365
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
×
1366
end
1367

UNCOV
1368
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
×
1369
    throw(CanonicalIndexError("getindex", typeof(A)))
UNCOV
1370
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
×
1371
    throw(CanonicalIndexError("getindex", typeof(A)))
1372
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
23,291,037✔
1373

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

1378
## IndexLinear Scalar indexing: canonical method is one Int
1379
_getindex(::IndexLinear, A::AbstractVector, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))  # ambiguity resolution in case packages specialize this (to be avoided if at all possible, but see Interpolations.jl)
22,765,622✔
1380
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
×
1381
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
14,678✔
1382
    @inline
14,678✔
1383
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
708,603✔
1384
    @inbounds r = getindex(A, _to_linear_index(A, I...))
708,603✔
1385
    r
14,678✔
1386
end
1387
_to_linear_index(A::AbstractArray, i::Integer) = i
×
1388
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
×
1389
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
×
1390
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
628,868✔
1391

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

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

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

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

1437
$(_DOCS_ALIASING_WARNING)
1438

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

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

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

1447
julia> A
1448
2×2 Matrix{Float64}:
1449
 10.0  30.0
1450
 20.0  40.0
1451
```
1452
"""
1453
function setindex!(A::AbstractArray, v, I...)
6,570✔
1454
    @_propagate_inbounds_meta
520,918✔
1455
    error_if_canonical_setindex(IndexStyle(A), A, I...)
520,918✔
1456
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
698,470✔
1457
end
1458
function unsafe_setindex!(A::AbstractArray, v, I...)
×
UNCOV
1459
    @inline
×
UNCOV
1460
    @inbounds r = setindex!(A, v, I...)
×
UNCOV
1461
    r
×
1462
end
1463

UNCOV
1464
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
×
1465
    throw(CanonicalIndexError("setindex!", typeof(A)))
UNCOV
1466
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
×
1467
    throw(CanonicalIndexError("setindex!", typeof(A)))
1468
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
514,348✔
1469

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

1474
## IndexLinear Scalar indexing
1475
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
584,394✔
1476
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
1477
    @inline
×
1478
    @boundscheck checkbounds(A, I...)
114,076✔
1479
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
114,076✔
1480
    r
×
1481
end
1482

1483
# IndexCartesian Scalar indexing
1484
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
×
UNCOV
1485
    @_propagate_inbounds_meta
×
UNCOV
1486
    setindex!(A, v, I...)
×
1487
end
UNCOV
1488
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
×
UNCOV
1489
    @inline
×
UNCOV
1490
    @boundscheck checkbounds(A, I...)
×
UNCOV
1491
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
×
UNCOV
1492
    r
×
1493
end
1494

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

1497
"""
1498
    parent(A)
1499

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

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

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

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

UNCOV
1525
parent(a::AbstractArray) = a
×
1526

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

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

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

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

1541
See also [`Base.mightalias`](@ref).
1542
"""
1543
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
381,839✔
1544
unalias(dest, A::AbstractRange) = A
24,665✔
1545
unalias(dest, A) = A
2✔
1546

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

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

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

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

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

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

1583
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
UNCOV
1584
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
UNCOV
1585
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
UNCOV
1586
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1587
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
381,764✔
UNCOV
1588
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
×
UNCOV
1589
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
UNCOV
1590
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
×
UNCOV
1591
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
×
1592

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

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

1598
Custom arrays that would like to opt-in to aliasing detection of their component
1599
parts can specialize this method to return the concatenation of the `dataids` of
1600
their component parts.  A typical definition for an array that wraps a parent is
1601
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1602
"""
1603
dataids(A::AbstractArray) = (UInt(objectid(A)),)
43✔
1604
dataids(A::Memory) = (UInt(A.ptr),)
763,485✔
1605
dataids(A::Array) = dataids(A.ref.mem)
763,276✔
UNCOV
1606
dataids(::AbstractRange) = ()
×
1607
dataids(x) = ()
×
1608

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

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

1614
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
4✔
1615
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
×
1616
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
×
1617
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
×
1618
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
×
1619
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
×
1620

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

UNCOV
1639
get(A::AbstractArray, I::AbstractRange, default) = get!(similar(A, typeof(default), index_shape(I)), A, I, default)
×
1640

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

UNCOV
1648
get(A::AbstractArray, I::RangeVecIntList, default) =
×
1649
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1650

1651
## structured matrix methods ##
1652
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
×
UNCOV
1653
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
×
1654

1655
## Concatenation ##
1656
eltypeof(x) = typeof(x)
1✔
1657
eltypeof(x::AbstractArray) = eltype(x)
3✔
1658

1659
promote_eltypeof() = error()
×
1660
promote_eltypeof(v1) = eltypeof(v1)
×
1661
promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2))
2✔
UNCOV
1662
promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...))
×
UNCOV
1663
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
×
UNCOV
1664
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
×
1665

1666
promote_eltype() = error()
×
UNCOV
1667
promote_eltype(v1) = eltype(v1)
×
1668
promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2))
×
1669
promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...))
×
1670
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
83✔
1671
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
6✔
1672

1673
#TODO: ERROR CHECK
1674
_cat(catdim::Int) = Vector{Any}()
×
1675

UNCOV
1676
typed_vcat(::Type{T}) where {T} = Vector{T}()
×
1677
typed_hcat(::Type{T}) where {T} = Vector{T}()
×
1678

1679
## cat: special cases
1680
vcat(X::T...) where {T}         = T[ X[i] for i=eachindex(X) ]
×
UNCOV
1681
vcat(X::T...) where {T<:Number} = T[ X[i] for i=eachindex(X) ]
×
1682
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=eachindex(X) ]
×
1683
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=eachindex(X) ]
×
1684

UNCOV
1685
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
×
UNCOV
1686
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
×
UNCOV
1687
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
×
UNCOV
1688
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
×
1689

UNCOV
1690
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
×
UNCOV
1691
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
×
1692

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

1698
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
3✔
1699
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
5✔
1700
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1701

1702
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
1703
    pos = 1
3✔
1704
    for k=1:Int(length(V))::Int
3✔
1705
        Vk = V[k]
83✔
1706
        p1 = pos + Int(length(Vk))::Int - 1
83✔
1707
        a[pos:p1] = Vk
103✔
1708
        pos = p1+1
83✔
1709
    end
163✔
1710
    a
3✔
1711
end
1712

UNCOV
1713
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
×
1714

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

1722

1723
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
×
1724
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
×
1725

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

1760
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
×
1761
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
×
1762

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

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

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

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

1791
## cat: general case
1792

1793
# helper functions
1794
cat_size(A) = (1,)
1✔
1795
cat_size(A::AbstractArray) = size(A)
3✔
UNCOV
1796
cat_size(A, d) = 1
×
1797
cat_size(A::AbstractArray, d) = size(A, d)
3✔
1798

UNCOV
1799
cat_length(::Any) = 1
×
UNCOV
1800
cat_length(a::AbstractArray) = length(a)
×
1801

UNCOV
1802
cat_ndims(a) = 0
×
1803
cat_ndims(a::AbstractArray) = ndims(a)
×
1804

1805
cat_indices(A, d) = OneTo(1)
1✔
1806
cat_indices(A::AbstractArray, d) = axes(A, d)
3✔
1807

1808
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1✔
1809
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
×
1810
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1✔
1811
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
×
1812
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
×
1813
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
×
1814

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

1830
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1831
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
×
UNCOV
1832
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
×
1833
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
×
1834
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1835
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
2✔
1836
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
UNCOV
1837
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
×
UNCOV
1838
    _cs(ndim, shape[1], 1)
×
UNCOV
1839
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
×
1840
end
UNCOV
1841
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
×
UNCOV
1842
    next = _cs(ndim, shape[1], nshape[1])
×
UNCOV
1843
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
×
1844
end
1845
@inline function _cshp(ndim::Int, dims, shape, nshape)
1846
    a = shape[1]
2✔
1847
    b = nshape[1]
2✔
1848
    next = dims[1] ? a + b : _cs(ndim, a, b)
2✔
1849
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
2✔
1850
end
1851

1852
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
×
1853
    "mismatch in dimension $d (expected $a got $b)")))
1854

UNCOV
1855
dims2cat(::Val{dims}) where dims = dims2cat(dims)
×
UNCOV
1856
function dims2cat(dims)
×
UNCOV
1857
    if any(≤(0), dims)
×
UNCOV
1858
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
×
1859
    end
UNCOV
1860
    ntuple(in(dims), maximum(dims))
×
1861
end
1862

1863
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
3✔
1864

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

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

1881
function __cat_offset!(A, shape, catdims, offsets, x, X...)
1✔
1882
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1883
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
5✔
1884
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
5✔
1885
end
1886
__cat_offset!(A, shape, catdims, offsets) = A
2✔
1887

1888
function __cat_offset1!(A, shape, catdims, offsets, x)
1889
    inds = ntuple(length(offsets)) do i
5✔
1890
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
5✔
1891
    end
1892
    _copy_or_fill!(A, inds, x)
6✔
1893
    newoffsets = ntuple(length(offsets)) do i
4✔
1894
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
4✔
1895
    end
1896
    return newoffsets
4✔
1897
end
1898

1899
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
1✔
1900
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
5✔
1901

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
2013
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
×
UNCOV
2014
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
×
2015

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

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

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

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

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

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

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

2040
# Examples
2041

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

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

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

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

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

2067
# Extended Help
2068

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

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

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

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

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

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

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

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

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

2112
julia> b = "bbb";
2113

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

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

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

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

UNCOV
2142
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
×
UNCOV
2143
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
×
2144
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
×
2145
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
×
UNCOV
2146
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
×
2147
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
×
2148

2149
# 2d horizontal and vertical concatenation
2150

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
2215
    a = Matrix{T}(undef, nr, nc)
×
2216
    if length(a) != length(xs)
×
2217
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
×
2218
    end
2219
    k = 1
×
2220
    @inbounds for i=1:nr
×
2221
        if nc != rows[i]
×
UNCOV
2222
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
×
2223
        end
2224
        for j=1:nc
×
2225
            a[i,j] = xs[k]
×
2226
            k += 1
×
2227
        end
×
2228
    end
×
UNCOV
2229
    a
×
2230
end
2231

2232
function hvcat_fill!(a::Array, xs::Tuple)
×
2233
    nr, nc = size(a,1), size(a,2)
×
2234
    len = length(xs)
×
2235
    if nr*nc != len
×
2236
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
×
2237
    end
UNCOV
2238
    k = 1
×
UNCOV
2239
    for i=1:nr
×
2240
        @inbounds for j=1:nc
×
2241
            a[i,j] = xs[k]
×
UNCOV
2242
            k += 1
×
2243
        end
×
UNCOV
2244
    end
×
2245
    a
×
2246
end
2247

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

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

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

2266
## N-dimensional concatenation ##
2267

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2363

2364
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
×
2365
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
×
2366

2367
# 1-dimensional hvncat methods
2368

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

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

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

UNCOV
2383
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
×
2384
    N < 0 &&
×
2385
        throw(ArgumentError("concatenation dimension must be non-negative"))
2386
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
×
2387
end
2388

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

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

2410
    nd = N
×
2411

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

2421
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
×
UNCOV
2422
    k = 1
×
UNCOV
2423
    for a ∈ as
×
2424
        for i ∈ eachindex(a)
×
2425
            A[k] = a[i]
×
UNCOV
2426
            k += 1
×
2427
        end
×
UNCOV
2428
    end
×
2429
    return A
×
2430
end
2431

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

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

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

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

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

2469

2470
# balanced dimensions hvncat methods
2471

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

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

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

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

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

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

2542
    d1 = row_first ? 2 : 1
×
2543
    d2 = row_first ? 1 : 2
×
2544

2545
    outdims = zeros(Int, N)
×
2546

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

2568
    # discover number of rows or columns
2569
    for i ∈ 1:dims[d1]
×
2570
        outdims[d1] += cat_size(as[i], d1)
×
2571
    end
×
2572

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

2607
    outlen = prod(outdims)
×
2608
    elementcount == outlen ||
×
2609
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2610

2611
    # copy into final array
UNCOV
2612
    A = cat_similar(as[1], T, ntuple(i -> outdims[i], N))
×
2613
    # @assert all(==(0), currentdims)
2614
    outdims .= 0
×
2615
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
×
UNCOV
2616
    return A
×
2617
end
2618

2619

2620
# unbalanced dimensions hvncat methods
2621

2622
function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
×
2623
    length(shape[1]) > 0 ||
×
2624
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
UNCOV
2625
    return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
×
2626
end
2627

UNCOV
2628
function _typed_hvncat(T::Type, shape::NTuple{N, Tuple}, row_first::Bool, as...) where {N}
×
2629
    # function barrier after calculating the max is necessary for high performance
UNCOV
2630
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
×
UNCOV
2631
    return _typed_hvncat_shape(T, (shape..., ntuple(x -> shape[end], nd - N)...), row_first, as)
×
2632
end
2633

UNCOV
2634
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
×
2635
    length(as) > 0 ||
×
2636
        throw(ArgumentError("must have at least one element"))
UNCOV
2637
    all(>(0), tuple((shape...)...)) ||
×
2638
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2639

2640
    d1 = row_first ? 2 : 1
×
2641
    d2 = row_first ? 1 : 2
×
2642

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

UNCOV
2658
    elementcount = 0
×
2659
    for i ∈ eachindex(as)
×
2660
        elementcount += cat_length(as[i])
×
2661
        wasstartblock = false
×
2662
        for d ∈ 1:N
×
UNCOV
2663
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
×
UNCOV
2664
            dsize = cat_size(as[i], ad)
×
UNCOV
2665
            blockcounts[d] += 1
×
2666

UNCOV
2667
            if d == 1 || i == 1 || wasstartblock
×
2668
                currentdims[d] += dsize
×
2669
            elseif dsize != cat_size(as[i - 1], ad)
×
2670
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
×
2671
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2672
            end
2673

UNCOV
2674
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
×
2675

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

UNCOV
2694
    outlen = prod(outdims)
×
UNCOV
2695
    elementcount == outlen ||
×
2696
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2697

2698
    if row_first
×
2699
        outdims[1], outdims[2] = outdims[2], outdims[1]
×
2700
    end
2701

2702
    # @assert all(==(0), currentdims)
2703
    # @assert all(==(0), blockcounts)
2704

2705
    # copy into final array
2706
    A = cat_similar(as[1], T, ntuple(i -> outdims[i], nd))
×
UNCOV
2707
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
×
2708
    return A
×
2709
end
2710

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

2729
                @inbounds for j ∈ 1:N
×
UNCOV
2730
                    inneroffsets[j] += 1
×
UNCOV
2731
                    inneroffsets[j] < cat_size(a, j) && break
×
2732
                    inneroffsets[j] = 0
×
2733
                end
×
2734
            end
×
2735
        else
2736
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
×
2737
            A[Ai] = a
×
2738
        end
2739

2740
        @inbounds for j ∈ (d1, d2, 3:N...)
×
UNCOV
2741
            offsets[j] += cat_size(a, j)
×
2742
            offsets[j] < outdims[j] && break
×
2743
            offsets[j] = 0
×
2744
        end
×
2745
    end
×
2746
end
2747

2748
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
×
2749
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2750
    Ai = inneroffsets[1] + offsets[1] + 1
×
UNCOV
2751
    for j ∈ 2:nd
×
UNCOV
2752
        increment = inneroffsets[j] + offsets[j]
×
UNCOV
2753
        for k ∈ 1:j-1
×
UNCOV
2754
            increment *= outdims[k]
×
UNCOV
2755
        end
×
UNCOV
2756
        Ai += increment
×
UNCOV
2757
    end
×
UNCOV
2758
    Ai
×
2759
end
2760

2761
"""
2762
    stack(iter; [dims])
2763

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

2767
By default the axes of the elements are placed first,
2768
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2769
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2770

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

2775
The various [`cat`](@ref) functions also combine arrays. However, these all
2776
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2777
the arrays along new dimensions.
2778
They also accept arrays as separate arguments, rather than a single collection.
2779

2780
!!! compat "Julia 1.9"
2781
    This function requires at least Julia 1.9.
2782

2783
# Examples
2784
```jldoctest
2785
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2786

2787
julia> mat = stack(vecs)
2788
2×3 Matrix{Float32}:
2789
 1.0  30.0  500.0
2790
 2.0  40.0  600.0
2791

2792
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2793
true
2794

2795
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2796
true
2797

2798
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2799
2×4 Matrix{Int64}:
2800
  1   2   3   4
2801
 10  11  12  13
2802

2803
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2804
true
2805

2806
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2807
3×2 Matrix{Float32}:
2808
   1.0    2.0
2809
  30.0   40.0
2810
 500.0  600.0
2811

2812
julia> x = rand(3,4);
2813

2814
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2815
true
2816
```
2817

2818
Higher-dimensional examples:
2819

2820
```jldoctest
2821
julia> A = rand(5, 7, 11);
2822

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

2825
julia> (element = size(first(E)), container = size(E))
2826
(element = (5, 11), container = (7,))
2827

2828
julia> stack(E) |> size
2829
(5, 11, 7)
2830

2831
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2832
true
2833

2834
julia> A == stack(E; dims=2)
2835
true
2836

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

2839
julia> (element = size(first(M)), container = size(M))
2840
(element = (2, 3), container = (5, 7))
2841

2842
julia> stack(M) |> size  # keeps all dimensions
2843
(2, 3, 5, 7)
2844

2845
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2846
(35, 2, 3)
2847

2848
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2849
(14, 15)
2850
```
2851
"""
UNCOV
2852
stack(iter; dims=:) = _stack(dims, iter)
×
2853

2854
"""
2855
    stack(f, args...; [dims])
2856

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

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

2864
See also [`mapslices`](@ref), [`eachcol`](@ref).
2865

2866
# Examples
2867
```jldoctest
2868
julia> stack(c -> (c, c-32), "julia")
2869
2×5 Matrix{Char}:
2870
 'j'  'u'  'l'  'i'  'a'
2871
 'J'  'U'  'L'  'I'  'A'
2872

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

2884
_stack(dims::Union{Integer, Colon}, iter) = _stack(dims, IteratorSize(iter), iter)
×
2885

2886
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
×
2887

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

2901
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
×
2902
    xit = iterate(A)
×
2903
    nothing === xit && return _empty_stack(:, T, S, A)
×
2904
    x1, _ = xit
×
2905
    ax1 = _iterator_axes(x1)
×
2906
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
×
2907
    off = firstindex(B)
×
2908
    len = length(x1)
×
UNCOV
2909
    while xit !== nothing
×
UNCOV
2910
        x, state = xit
×
2911
        _stack_size_check(x, ax1)
×
2912
        copyto!(B, off, x)
×
2913
        off += len
×
UNCOV
2914
        xit = iterate(A, state)
×
UNCOV
2915
    end
×
2916
    B
×
2917
end
2918

UNCOV
2919
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
×
2920
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
×
2921
_iterator_axes(x, ::IteratorSize) = axes(x)
×
2922

2923
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2924
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
×
2925
    _typed_stack(dims, T, S, IteratorSize(S), A)
UNCOV
2926
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
×
2927
    _typed_stack(dims, T, S, HasShape{1}(), A)
UNCOV
2928
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
×
UNCOV
2929
    if dims == N+1
×
2930
        _typed_stack(:, T, S, A, (_vec_axis(A),))
×
2931
    else
2932
        _dim_stack(dims, T, S, A)
×
2933
    end
2934
end
2935
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
×
2936
    _dim_stack(dims, T, S, A)
2937

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

2940
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
×
2941
    xit = Iterators.peel(A)
×
2942
    nothing === xit && return _empty_stack(dims, T, S, A)
×
UNCOV
2943
    x1, xrest = xit
×
2944
    ax1 = _iterator_axes(x1)
×
2945
    N1 = length(ax1)+1
×
2946
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
×
2947

UNCOV
2948
    newaxis = _vec_axis(A)
×
2949
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
×
UNCOV
2950
    B = similar(_ensure_array(x1), T, outax...)
×
2951

UNCOV
2952
    if dims == 1
×
UNCOV
2953
        _dim_stack!(Val(1), B, x1, xrest)
×
2954
    elseif dims == 2
×
2955
        _dim_stack!(Val(2), B, x1, xrest)
×
2956
    else
UNCOV
2957
        _dim_stack!(Val(dims), B, x1, xrest)
×
2958
    end
2959
    B
×
2960
end
2961

2962
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
×
2963
    before = ntuple(d -> Colon(), dims - 1)
×
2964
    after = ntuple(d -> Colon(), ndims(B) - dims)
×
2965

UNCOV
2966
    i = firstindex(B, dims)
×
UNCOV
2967
    copyto!(view(B, before..., i, after...), x1)
×
2968

2969
    for x in xrest
×
2970
        _stack_size_check(x, _iterator_axes(x1))
×
2971
        i += 1
×
2972
        @inbounds copyto!(view(B, before..., i, after...), x)
×
UNCOV
2973
    end
×
2974
end
2975

UNCOV
2976
@inline function _stack_size_check(x, ax1::Tuple)
×
2977
    if _iterator_axes(x) != ax1
×
2978
        uax1 = map(UnitRange, ax1)
×
UNCOV
2979
        uaxN = map(UnitRange, _iterator_axes(x))
×
2980
        throw(DimensionMismatch(
×
2981
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
2982
    end
2983
end
2984

UNCOV
2985
_ensure_array(x::AbstractArray) = x
×
UNCOV
2986
_ensure_array(x) = 1:0  # passed to similar, makes stack's output an Array
×
2987

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

2990

2991
## Reductions and accumulates ##
2992

2993
function isequal(A::AbstractArray, B::AbstractArray)
2994
    if A === B return true end
1,420✔
2995
    if axes(A) != axes(B)
2,720✔
UNCOV
2996
        return false
×
2997
    end
2998
    for (a, b) in zip(A, B)
2,710✔
2999
        if !isequal(a, b)
161,045✔
3000
            return false
247✔
3001
        end
3002
    end
320,493✔
3003
    return true
1,113✔
3004
end
3005

UNCOV
3006
function cmp(A::AbstractVector, B::AbstractVector)
×
UNCOV
3007
    for (a, b) in zip(A, B)
×
UNCOV
3008
        if !isequal(a, b)
×
UNCOV
3009
            return isless(a, b) ? -1 : 1
×
3010
        end
UNCOV
3011
    end
×
3012
    return cmp(length(A), length(B))
×
3013
end
3014

3015
"""
3016
    isless(A::AbstractArray{<:Any,0}, B::AbstractArray{<:Any,0})
3017

3018
Return `true` when the only element of `A` is less than the only element of `B`.
3019
"""
UNCOV
3020
function isless(A::AbstractArray{<:Any,0}, B::AbstractArray{<:Any,0})
×
3021
    isless(only(A), only(B))
×
3022
end
3023

3024
"""
3025
    isless(A::AbstractVector, B::AbstractVector)
3026

3027
Return `true` when `A` is less than `B` in lexicographic order.
3028
"""
UNCOV
3029
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
×
3030

3031
function (==)(A::AbstractArray, B::AbstractArray)
233✔
3032
    if axes(A) != axes(B)
405,828✔
UNCOV
3033
        return false
×
3034
    end
3035
    anymissing = false
233✔
3036
    for (a, b) in zip(A, B)
405,825✔
3037
        eq = (a == b)
2,641,823✔
3038
        if ismissing(eq)
596✔
UNCOV
3039
            anymissing = true
×
3040
        elseif !eq
1,322,078✔
3041
            return false
59✔
3042
        end
3043
    end
2,440,728✔
3044
    return anymissing ? missing : true
202,967✔
3045
end
3046

3047
# _sub2ind and _ind2sub
3048
# fallbacks
3049
function _sub2ind(A::AbstractArray, I...)
UNCOV
3050
    @inline
×
3051
    _sub2ind(axes(A), I...)
628,868✔
3052
end
3053

3054
function _ind2sub(A::AbstractArray, ind)
×
3055
    @inline
×
UNCOV
3056
    _ind2sub(axes(A), ind)
×
3057
end
3058

3059
# 0-dimensional arrays and indexing with []
UNCOV
3060
_sub2ind(::Tuple{}) = 1
×
UNCOV
3061
_sub2ind(::DimsInteger) = 1
×
3062
_sub2ind(::Indices) = 1
×
UNCOV
3063
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
×
3064

3065
# Generic cases
UNCOV
3066
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
×
3067
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
628,868✔
3068
# In 1d, there's a question of whether we're doing cartesian indexing
3069
# or linear indexing. Support only the former.
3070
_sub2ind(inds::Indices{1}, I::Integer...) =
×
3071
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
UNCOV
3072
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
3073
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
3074

UNCOV
3075
_sub2ind_recurse(::Any, L, ind) = ind
×
UNCOV
3076
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
×
UNCOV
3077
    @inline
×
3078
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
×
3079
end
3080
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
3081
    @inline
×
UNCOV
3082
    r1 = inds[1]
×
3083
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
1,257,736✔
3084
end
3085

3086
nextL(L, l::Integer) = L*l
×
3087
nextL(L, r::AbstractUnitRange) = L*length(r)
628,868✔
UNCOV
3088
nextL(L, r::Slice) = L*length(r.indices)
×
3089
offsetin(i, l::Integer) = i-1
×
3090
offsetin(i, r::AbstractUnitRange) = i-first(r)
1,257,736✔
3091

3092
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
3093
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
×
3094
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
×
UNCOV
3095
_ind2sub(inds::Indices{1}, ind::Integer) =
×
3096
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3097
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
×
3098

3099
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3100
function _ind2sub_recurse(indslast::NTuple{1}, ind)
×
UNCOV
3101
    @inline
×
UNCOV
3102
    (_lookup(ind, indslast[1]),)
×
3103
end
3104
function _ind2sub_recurse(inds, ind)
×
3105
    @inline
×
3106
    r1 = inds[1]
×
UNCOV
3107
    indnext, f, l = _div(ind, r1)
×
UNCOV
3108
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
×
3109
end
3110

UNCOV
3111
_lookup(ind, d::Integer) = ind+1
×
3112
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
×
UNCOV
3113
_div(ind, d::Integer) = div(ind, d), 1, d
×
3114
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
×
3115

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

UNCOV
3135
function _sub2ind!(Iout, inds, Iinds, I)
×
3136
    @noinline
×
3137
    for i in Iinds
×
3138
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
UNCOV
3139
        Iout[i] = sub2ind_vec(inds, i, I)
×
3140
    end
×
3141
    Iout
×
3142
end
3143

3144
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3145
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3146
_sub2ind_vec(i) = ()
×
3147

3148
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3149
    M = length(ind)
×
UNCOV
3150
    t = ntuple(n->similar(ind),Val(N))
×
UNCOV
3151
    for (i,idx) in pairs(IndexLinear(), ind)
×
UNCOV
3152
        sub = _ind2sub(inds, idx)
×
UNCOV
3153
        for j = 1:N
×
UNCOV
3154
            t[j][i] = sub[j]
×
UNCOV
3155
        end
×
UNCOV
3156
    end
×
UNCOV
3157
    t
×
3158
end
3159

3160
## iteration utilities ##
3161

3162
"""
3163
    foreach(f, c...) -> nothing
3164

3165
Call function `f` on each element of iterable `c`.
3166
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3167
any iterator is finished.
3168

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

3172
# Examples
3173
```jldoctest
3174
julia> tri = 1:3:7; res = Int[];
3175

3176
julia> foreach(x -> push!(res, x^2), tri)
3177

3178
julia> res
3179
3-element Vector{$(Int)}:
3180
  1
3181
 16
3182
 49
3183

3184
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3185
1 with a
3186
4 with b
3187
7 with c
3188
```
3189
"""
3190
foreach(f, itr) = (for x in itr; f(x); end; nothing)
3,133,161✔
UNCOV
3191
foreach(f, itr, itrs...) = (for z in zip(itr, itrs...); f(z...); end; nothing)
×
3192

3193
## map over arrays ##
3194

3195
## transform any set of dimensions
3196
## dims specifies which dimensions will be transformed. for example
3197
## dims==1:2 will call f on all slices A[:,:,...]
3198
"""
3199
    mapslices(f, A; dims)
3200

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

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

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

3210
# Examples
3211
```jldoctest
3212
julia> A = reshape(1:30,(2,5,3))
3213
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3214
[:, :, 1] =
3215
 1  3  5  7   9
3216
 2  4  6  8  10
3217

3218
[:, :, 2] =
3219
 11  13  15  17  19
3220
 12  14  16  18  20
3221

3222
[:, :, 3] =
3223
 21  23  25  27  29
3224
 22  24  26  28  30
3225

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

3228
julia> B = mapslices(f, A, dims=(1,2))
3229
1×4×3 Array{$Int, 3}:
3230
[:, :, 1] =
3231
 1  1  1  1
3232

3233
[:, :, 2] =
3234
 11  11  11  11
3235

3236
[:, :, 3] =
3237
 21  21  21  21
3238

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

3241
julia> B == stack(f2, eachslice(A, dims=3))
3242
true
3243

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

3246
julia> mapslices(g, A, dims=[1,3])
3247
1×5×1 Array{Rational{$Int}, 3}:
3248
[:, :, 1] =
3249
 1//21  3//23  1//5  7//27  9//29
3250

3251
julia> map(g, eachslice(A, dims=2))
3252
5-element Vector{Rational{$Int}}:
3253
 1//21
3254
 3//23
3255
 1//5
3256
 7//27
3257
 9//29
3258

3259
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3260
true
3261
```
3262

3263
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3264
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3265
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3266
values in the slice without affecting `A`.
3267
"""
UNCOV
3268
@constprop :aggressive function mapslices(f, A::AbstractArray; dims)
×
3269
    isempty(dims) && return map(f, A)
×
3270

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

3281
    # Apply the function to the first slice in order to determine the next steps
3282
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
×
UNCOV
3283
    Aslice = A[idx1...]
×
3284
    r1 = f(Aslice)
×
3285

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

3302
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3303
    din = Ref(0)
×
UNCOV
3304
    Rsize = ntuple(ndims(A)) do d
×
UNCOV
3305
        if d in dims
×
UNCOV
3306
            axes(res1, din[] += 1)
×
3307
        else
3308
            axes(A,d)
×
3309
        end
3310
    end
3311
    R = similar(res1, Rsize)
×
3312

3313
    # Determine iteration space. It will be convenient in the loop to mask N-dimensional
3314
    # CartesianIndices, with some trivial dimensions:
UNCOV
3315
    itershape = ntuple(d -> d in dims ? Base.OneTo(1) : axes(A,d), ndims(A))
×
UNCOV
3316
    indices = Iterators.drop(CartesianIndices(itershape), 1)
×
3317

3318
    # That skips the first element, which we already have:
UNCOV
3319
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
×
UNCOV
3320
    concatenate_setindex!(R, res1, ridx...)
×
3321

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

UNCOV
3329
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
×
3330
    return R
×
3331
end
3332

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

UNCOV
3360
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
×
UNCOV
3361
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
×
3362

3363
## 1 argument
3364

3365
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
527,182✔
3366
    for (i,j) in zip(eachindex(dest),eachindex(A))
4,496,141✔
3367
        val = f(@inbounds A[j])
4,350,062✔
3368
        @inbounds dest[i] = val
3,292,750✔
3369
    end
4,062,040✔
3370
    return dest
2,639,433✔
3371
end
3372

3373
# map on collections
3374
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
217✔
3375

3376
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
4✔
UNCOV
3377
mapany(f, itr) = Any[f(x) for x in itr]
×
3378

3379
"""
3380
    map(f, c...) -> collection
3381

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

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

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

3389
# Examples
3390
```jldoctest
3391
julia> map(x -> x * 2, [1, 2, 3])
3392
3-element Vector{Int64}:
3393
 2
3394
 4
3395
 6
3396

3397
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3398
3-element Vector{Int64}:
3399
 11
3400
 22
3401
 33
3402
```
3403
"""
3404
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
2✔
3405

3406
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
×
3407
map(f, ::AbstractSet) = error("map is not defined on sets")
×
3408

3409
## 2 argument
UNCOV
3410
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
×
UNCOV
3411
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
×
UNCOV
3412
        @inbounds a, b = A[j], B[k]
×
3413
        val = f(a, b)
×
3414
        @inbounds dest[i] = val
×
3415
    end
×
3416
    return dest
×
3417
end
3418

3419
## N argument
3420

3421
@inline ith_all(i, ::Tuple{}) = ()
×
3422
function ith_all(i, as)
×
3423
    @_propagate_inbounds_meta
×
3424
    return (as[1][i], ith_all(i, tail(as))...)
×
3425
end
3426

UNCOV
3427
function map_n!(f::F, dest::AbstractArray, As) where F
×
3428
    idxs = LinearIndices(dest)
×
3429
    if all(x -> LinearIndices(x) == idxs, As)
×
3430
        for i in idxs
×
3431
            @inbounds as = ith_all(i, As)
×
3432
            val = f(as...)
×
UNCOV
3433
            @inbounds dest[i] = val
×
3434
        end
×
3435
    else
UNCOV
3436
        for (i, Is...) in zip(eachindex(dest), map(eachindex, As)...)
×
UNCOV
3437
            as = ntuple(j->getindex(As[j], Is[j]), length(As))
×
UNCOV
3438
            val = f(as...)
×
UNCOV
3439
            dest[i] = val
×
UNCOV
3440
        end
×
3441
    end
UNCOV
3442
    return dest
×
3443
end
3444

3445
"""
3446
    map!(function, destination, collection...)
3447

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

3451
$(_DOCS_ALIASING_WARNING)
3452

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

3455
# Examples
3456
```jldoctest
3457
julia> a = zeros(3);
3458

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

3461
julia> a
3462
3-element Vector{Float64}:
3463
 2.0
3464
 4.0
3465
 6.0
3466

3467
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3468
5-element Vector{$(Int)}:
3469
 101
3470
 103
3471
 105
3472
   0
3473
   0
3474
```
3475
"""
UNCOV
3476
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
×
UNCOV
3477
    @assert !isempty(As) # should dispatch to map!(f, A)
×
UNCOV
3478
    map_n!(f, dest, As)
×
3479
end
3480

3481
"""
3482
    map!(function, array)
3483

3484
Like [`map`](@ref), but stores the result in the same array.
3485
!!! compat "Julia 1.12"
3486
    This method requires Julia 1.12 or later. To support previous versions too,
3487
    use the equivalent `map!(function, array, array)`.
3488

3489
# Examples
3490
```jldoctest
3491
julia> a = [1 2 3; 4 5 6];
3492

3493
julia> map!(x -> x^3, a);
3494

3495
julia> a
3496
2×3 Matrix{$Int}:
3497
  1    8   27
3498
 64  125  216
3499
```
3500
"""
UNCOV
3501
map!(f::F, inout::AbstractArray) where F = map!(f, inout, inout)
×
3502

3503
"""
3504
    map(f, A::AbstractArray...) -> N-array
3505

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

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

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

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

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

3530
# Generic versions of push! for AbstractVector
3531
# These are specialized further for Vector for faster resizing and setindexing
UNCOV
3532
function push!(a::AbstractVector{T}, item) where T
×
3533
    # convert first so we don't grow the array if the assignment won't work
3534
    itemT = item isa T ? item : convert(T, item)::T
×
3535
    new_length = length(a) + 1
×
3536
    resize!(a, new_length)
×
3537
    a[end] = itemT
×
3538
    return a
×
3539
end
3540

3541
# specialize and optimize the single argument case
3542
function push!(a::AbstractVector{Any}, @nospecialize x)
×
3543
    new_length = length(a) + 1
×
3544
    resize!(a, new_length)
×
3545
    a[end] = x
×
3546
    return a
×
3547
end
3548
function push!(a::AbstractVector{Any}, @nospecialize x...)
×
3549
    @_terminates_locally_meta
×
UNCOV
3550
    na = length(a)
×
UNCOV
3551
    nx = length(x)
×
UNCOV
3552
    resize!(a, na + nx)
×
UNCOV
3553
    e = lastindex(a) - nx
×
3554
    for i = 1:nx
×
3555
        a[e+i] = x[i]
×
3556
    end
×
3557
    return a
×
3558
end
3559

3560
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3561
# (note: must not cause a dispatch loop when 1-item case is not defined)
UNCOV
3562
push!(A, a, b) = push!(push!(A, a), b)
×
UNCOV
3563
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
×
UNCOV
3564
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
UNCOV
3565
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
×
3566

3567
# sizehint! does not nothing by default
UNCOV
3568
sizehint!(a::AbstractVector, _) = a
×
3569

3570
## hashing AbstractArray ##
3571

3572
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3573
function hash(A::AbstractArray, h::UInt)
1,894✔
3574
    h ⊻= hash_abstractarray_seed
1,894✔
3575
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3576
    # Instead hash the tuple of firsts and lasts along each dimension
3577
    h = hash(map(first, axes(A)), h)
1,894✔
3578
    h = hash(map(last, axes(A)), h)
1,894✔
3579

3580
    # For short arrays, it's not worth doing anything complicated
3581
    if length(A) < 8192
1,894✔
3582
        for x in A
3,774✔
3583
            h = hash(x, h)
269,682✔
3584
        end
537,476✔
3585
        return h
1,894✔
3586
    end
3587

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

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

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

3609
    # Start at the last index
3610
    keyidx = last(ks)
×
3611
    linidx = key_to_linear[keyidx]
×
UNCOV
3612
    fibskip = prevfibskip = oneunit(linidx)
×
UNCOV
3613
    first_linear = first(LinearIndices(linear_to_key))
×
3614
    n = 0
×
3615
    while true
×
3616
        n += 1
×
3617
        # Hash the element
UNCOV
3618
        elt = A[keyidx]
×
UNCOV
3619
        h = hash(keyidx=>elt, h)
×
3620

3621
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
UNCOV
3622
        linidx = key_to_linear[keyidx]
×
UNCOV
3623
        linidx < fibskip + first_linear && break
×
UNCOV
3624
        linidx -= fibskip
×
3625
        keyidx = linear_to_key[linidx]
×
3626

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

3637
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3638
        keyidx = findprev(!isequal(elt), A, keyidx)
×
3639
        keyidx === nothing && break
×
UNCOV
3640
    end
×
3641

3642
    return h
×
3643
end
3644

3645
# The semantics of `collect` are weird. Better to write our own
UNCOV
3646
function rest(a::AbstractArray{T}, state...) where {T}
×
UNCOV
3647
    v = Vector{T}(undef, 0)
×
3648
    # assume only very few items are taken from the front
UNCOV
3649
    sizehint!(v, length(a))
×
3650
    return foldl(push!, Iterators.rest(a, state...), init=v)
×
3651
end
3652

3653

3654
## keepat! ##
3655

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

3658
function _keepat!(a::AbstractVector, inds)
×
3659
    local prev
×
UNCOV
3660
    i = firstindex(a)
×
3661
    for k in inds
×
3662
        if @isdefined(prev)
×
3663
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
×
3664
        end
3665
        ak = a[k] # must happen even when i==k for bounds checking
×
UNCOV
3666
        if i != k
×
UNCOV
3667
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
×
3668
        end
3669
        prev = k
×
3670
        i = nextind(a, i)
×
3671
    end
×
3672
    deleteat!(a, i:lastindex(a))
×
3673
    return a
×
3674
end
3675

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

3690
"""
3691
    circshift!(a::AbstractVector, shift::Integer)
3692

3693
Circularly shift, or rotate, the data in vector `a` by `shift` positions.
3694

3695
# Examples
3696

3697
```jldoctest
3698
julia> circshift!([1, 2, 3, 4, 5], 2)
3699
5-element Vector{Int64}:
3700
 4
3701
 5
3702
 1
3703
 2
3704
 3
3705

3706
julia> circshift!([1, 2, 3, 4, 5], -2)
3707
5-element Vector{Int64}:
3708
 3
3709
 4
3710
 5
3711
 1
3712
 2
3713
```
3714
"""
3715
function circshift!(a::AbstractVector, shift::Integer)
×
3716
    n = length(a)
×
UNCOV
3717
    n == 0 && return a
×
UNCOV
3718
    shift = mod(shift, n)
×
UNCOV
3719
    shift == 0 && return a
×
UNCOV
3720
    l = lastindex(a)
×
UNCOV
3721
    reverse!(a, firstindex(a), l-shift)
×
UNCOV
3722
    reverse!(a, l-shift+1, lastindex(a))
×
UNCOV
3723
    reverse!(a)
×
UNCOV
3724
    return a
×
3725
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