StatProfilerHTML.jl report
Generated on Thu, 21 Dec 2023 13:06:16
File source code
Line Exclusive Inclusive Code
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
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
77 d::Integer <= N ? axes(A)[d] : OneTo(1)
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)
97 @inline
98 map(oneto, size(A))
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(A) = _any_tuple(x->Int(first(x))::Int != 1, false, axes(A)...)
111 has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
112 # Use `_any_tuple` to avoid unneeded invoke.
113 # note: this could call `any` directly if the compiler can infer it
114 has_offset_axes(As...) = _any_tuple(has_offset_axes, false, As...)
115 has_offset_axes(::Colon) = false
116 has_offset_axes(::Array) = false
117
118 """
119 require_one_based_indexing(A::AbstractArray)
120 require_one_based_indexing(A,B...)
121
122 Throw an `ArgumentError` if the indices of any argument start with something other than `1` along any axis.
123 See also [`has_offset_axes`](@ref).
124
125 !!! compat "Julia 1.2"
126 This function requires at least Julia 1.2.
127 """
128 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"))
129
130 # Performance optimization: get rid of a branch on `d` in `axes(A, d)`
131 # for d=1. 1d arrays are heavily used, and the first dimension comes up
132 # in other applications.
133 axes1(A::AbstractArray{<:Any,0}) = OneTo(1)
134 axes1(A::AbstractArray) = (@inline; axes(A)[1])
135 axes1(iter) = oneto(length(iter))
136
137 """
138 keys(a::AbstractArray)
139
140 Return an efficient array describing all valid indices for `a` arranged in the shape of `a` itself.
141
142 The keys of 1-dimensional arrays (vectors) are integers, whereas all other N-dimensional
143 arrays use [`CartesianIndex`](@ref) to describe their locations. Often the special array
144 types [`LinearIndices`](@ref) and [`CartesianIndices`](@ref) are used to efficiently
145 represent these arrays of integers and `CartesianIndex`es, respectively.
146
147 Note that the `keys` of an array might not be the most efficient index type; for maximum
148 performance use [`eachindex`](@ref) instead.
149
150 # Examples
151 ```jldoctest
152 julia> keys([4, 5, 6])
153 3-element LinearIndices{1, Tuple{Base.OneTo{Int64}}}:
154 1
155 2
156 3
157
158 julia> keys([4 5; 6 7])
159 CartesianIndices((2, 2))
160 ```
161 """
162 keys(a::AbstractArray) = CartesianIndices(axes(a))
163 keys(a::AbstractVector) = LinearIndices(a)
164
165 """
166 keytype(T::Type{<:AbstractArray})
167 keytype(A::AbstractArray)
168
169 Return the key type of an array. This is equal to the
170 [`eltype`](@ref) of the result of `keys(...)`, and is provided
171 mainly for compatibility with the dictionary interface.
172
173 # Examples
174 ```jldoctest
175 julia> keytype([1, 2, 3]) == Int
176 true
177
178 julia> keytype([1 2; 3 4])
179 CartesianIndex{2}
180 ```
181
182 !!! compat "Julia 1.2"
183 For arrays, this function requires at least Julia 1.2.
184 """
185 keytype(a::AbstractArray) = keytype(typeof(a))
186 keytype(::Type{Union{}}, slurp...) = eltype(Union{})
187
188 keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
189 keytype(A::Type{<:AbstractVector}) = Int
190
191 valtype(a::AbstractArray) = valtype(typeof(a))
192 valtype(::Type{Union{}}, slurp...) = eltype(Union{})
193
194 """
195 valtype(T::Type{<:AbstractArray})
196 valtype(A::AbstractArray)
197
198 Return the value type of an array. This is identical to [`eltype`](@ref) and is
199 provided mainly for compatibility with the dictionary interface.
200
201 # Examples
202 ```jldoctest
203 julia> valtype(["one", "two", "three"])
204 String
205 ```
206
207 !!! compat "Julia 1.2"
208 For arrays, this function requires at least Julia 1.2.
209 """
210 valtype(A::Type{<:AbstractArray}) = eltype(A)
211
212 prevind(::AbstractArray, i::Integer) = Int(i)-1
213 nextind(::AbstractArray, i::Integer) = Int(i)+1
214
215
216 """
217 eltype(type)
218
219 Determine the type of the elements generated by iterating a collection of the given `type`.
220 For dictionary types, this will be a `Pair{KeyType,ValType}`. The definition
221 `eltype(x) = eltype(typeof(x))` is provided for convenience so that instances can be passed
222 instead of types. However the form that accepts a type argument should be defined for new
223 types.
224
225 See also: [`keytype`](@ref), [`typeof`](@ref).
226
227 # Examples
228 ```jldoctest
229 julia> eltype(fill(1f0, (2,2)))
230 Float32
231
232 julia> eltype(fill(0x1, (2,2)))
233 UInt8
234 ```
235 """
236 eltype(::Type) = Any
237 eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
238 eltype(x) = eltype(typeof(x))
239 eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
240
241 """
242 elsize(type)
243
244 Compute the memory stride in bytes between consecutive elements of [`eltype`](@ref)
245 stored inside the given `type`, if the array elements are stored densely with a
246 uniform linear stride.
247
248 # Examples
249 ```jldoctest
250 julia> Base.elsize(rand(Float32, 10))
251 4
252 ```
253 """
254 elsize(A::AbstractArray) = elsize(typeof(A))
255
256 """
257 ndims(A::AbstractArray) -> Integer
258
259 Return the number of dimensions of `A`.
260
261 See also: [`size`](@ref), [`axes`](@ref).
262
263 # Examples
264 ```jldoctest
265 julia> A = fill(1, (3,4,5));
266
267 julia> ndims(A)
268 3
269 ```
270 """
271 ndims(::AbstractArray{T,N}) where {T,N} = N
272 ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N
273 ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
274
275 """
276 length(collection) -> Integer
277
278 Return the number of elements in the collection.
279
280 Use [`lastindex`](@ref) to get the last valid index of an indexable collection.
281
282 See also: [`size`](@ref), [`ndims`](@ref), [`eachindex`](@ref).
283
284 # Examples
285 ```jldoctest
286 julia> length(1:5)
287 5
288
289 julia> length([1, 2, 3, 4])
290 4
291
292 julia> length([1 2; 3 4])
293 4
294 ```
295 """
296 length
297
298 """
299 length(A::AbstractArray)
300
301 Return the number of elements in the array, defaults to `prod(size(A))`.
302
303 # Examples
304 ```jldoctest
305 julia> length([1, 2, 3, 4])
306 4
307
308 julia> length([1 2; 3 4])
309 4
310 ```
311 """
312 length(t::AbstractArray) = (@inline; prod(size(t)))
313
314 # `eachindex` is mostly an optimization of `keys`
315 eachindex(itrs...) = keys(itrs...)
316
317 # eachindex iterates over all indices. IndexCartesian definitions are later.
318 eachindex(A::AbstractVector) = (@inline(); axes1(A))
319
320
321 @noinline function throw_eachindex_mismatch_indices(::IndexLinear, inds...)
322 throw(DimensionMismatch("all inputs to eachindex must have the same indices, got $(join(inds, ", ", " and "))"))
323 end
324 @noinline function throw_eachindex_mismatch_indices(::IndexCartesian, inds...)
325 throw(DimensionMismatch("all inputs to eachindex must have the same axes, got $(join(inds, ", ", " and "))"))
326 end
327
328 """
329 eachindex(A...)
330 eachindex(::IndexStyle, A::AbstractArray...)
331
332 Create an iterable object for visiting each index of an `AbstractArray` `A` in an efficient
333 manner. For array types that have opted into fast linear indexing (like `Array`), this is
334 simply the range `1:length(A)` if they use 1-based indexing.
335 For array types that have not opted into fast linear indexing, a specialized Cartesian
336 range is typically returned to efficiently index into the array with indices specified
337 for every dimension.
338
339 In general `eachindex` accepts arbitrary iterables, including strings and dictionaries, and returns
340 an iterator object supporting arbitrary index types (e.g. unevenly spaced or non-integer indices).
341
342 If `A` is `AbstractArray` it is possible to explicitly specify the style of the indices that
343 should be returned by `eachindex` by passing a value having `IndexStyle` type as its first argument
344 (typically `IndexLinear()` if linear indices are required or `IndexCartesian()` if Cartesian
345 range is wanted).
346
347 If you supply more than one `AbstractArray` argument, `eachindex` will create an
348 iterable object that is fast for all arguments (typically a [`UnitRange`](@ref)
349 if all inputs have fast linear indexing, a [`CartesianIndices`](@ref) otherwise).
350 If the arrays have different sizes and/or dimensionalities, a `DimensionMismatch` exception
351 will be thrown.
352
353 See also [`pairs`](@ref)`(A)` to iterate over indices and values together,
354 and [`axes`](@ref)`(A, 2)` for valid indices along one dimension.
355
356 # Examples
357 ```jldoctest
358 julia> A = [10 20; 30 40];
359
360 julia> for i in eachindex(A) # linear indexing
361 println("A[", i, "] == ", A[i])
362 end
363 A[1] == 10
364 A[2] == 30
365 A[3] == 20
366 A[4] == 40
367
368 julia> for i in eachindex(view(A, 1:2, 1:1)) # Cartesian indexing
369 println(i)
370 end
371 CartesianIndex(1, 1)
372 CartesianIndex(2, 1)
373 ```
374 """
375 eachindex(A::AbstractArray) = (@inline(); eachindex(IndexStyle(A), A))
376
377 function eachindex(A::AbstractArray, B::AbstractArray)
378 @inline
379 eachindex(IndexStyle(A,B), A, B)
380 end
381 function eachindex(A::AbstractArray, B::AbstractArray...)
382 @inline
383 eachindex(IndexStyle(A,B...), A, B...)
384 end
385 eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
386 eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
387 function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
388 @inline
389 indsA = eachindex(IndexLinear(), A)
390 _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
391 throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
392 indsA
393 end
394 function _all_match_first(f::F, inds, A, B...) where F<:Function
395 @inline
396 (inds == f(A)) & _all_match_first(f, inds, B...)
397 end
398 _all_match_first(f::F, inds) where F<:Function = true
399
400 # keys with an IndexStyle
401 keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...)
402
403 """
404 lastindex(collection) -> Integer
405 lastindex(collection, d) -> Integer
406
407 Return the last index of `collection`. If `d` is given, return the last index of `collection` along dimension `d`.
408
409 The syntaxes `A[end]` and `A[end, end]` lower to `A[lastindex(A)]` and
410 `A[lastindex(A, 1), lastindex(A, 2)]`, respectively.
411
412 See also: [`axes`](@ref), [`firstindex`](@ref), [`eachindex`](@ref), [`prevind`](@ref).
413
414 # Examples
415 ```jldoctest
416 julia> lastindex([1,2,4])
417 3
418
419 julia> lastindex(rand(3,4,5), 2)
420 4
421 ```
422 """
423 lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
424 lastindex(a, d) = (@inline; last(axes(a, d)))
425
426 """
427 firstindex(collection) -> Integer
428 firstindex(collection, d) -> Integer
429
430 Return the first index of `collection`. If `d` is given, return the first index of `collection` along dimension `d`.
431
432 The syntaxes `A[begin]` and `A[1, begin]` lower to `A[firstindex(A)]` and
433 `A[1, firstindex(A, 2)]`, respectively.
434
435 See also: [`first`](@ref), [`axes`](@ref), [`lastindex`](@ref), [`nextind`](@ref).
436
437 # Examples
438 ```jldoctest
439 julia> firstindex([1,2,4])
440 1
441
442 julia> firstindex(rand(3,4,5), 2)
443 1
444 ```
445 """
446 firstindex(a::AbstractArray) = (@inline; first(eachindex(IndexLinear(), a)))
447 firstindex(a, d) = (@inline; first(axes(a, d)))
448
449 first(a::AbstractArray) = a[first(eachindex(a))]
450
451 """
452 first(coll)
453
454 Get the first element of an iterable collection. Return the start point of an
455 [`AbstractRange`](@ref) even if it is empty.
456
457 See also: [`only`](@ref), [`firstindex`](@ref), [`last`](@ref).
458
459 # Examples
460 ```jldoctest
461 julia> first(2:2:10)
462 2
463
464 julia> first([1; 2; 3; 4])
465 1
466 ```
467 """
468 function first(itr)
469 x = iterate(itr)
470 x === nothing && throw(ArgumentError("collection must be non-empty"))
471 x[1]
472 end
473
474 """
475 first(itr, n::Integer)
476
477 Get the first `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
478 long enough.
479
480 See also: [`startswith`](@ref), [`Iterators.take`](@ref).
481
482 !!! compat "Julia 1.6"
483 This method requires at least Julia 1.6.
484
485 # Examples
486 ```jldoctest
487 julia> first(["foo", "bar", "qux"], 2)
488 2-element Vector{String}:
489 "foo"
490 "bar"
491
492 julia> first(1:6, 10)
493 1:6
494
495 julia> first(Bool[], 1)
496 Bool[]
497 ```
498 """
499 first(itr, n::Integer) = collect(Iterators.take(itr, n))
500 # Faster method for vectors
501 function first(v::AbstractVector, n::Integer)
502 n < 0 && throw(ArgumentError("Number of elements must be nonnegative"))
503 v[range(begin, length=min(n, checked_length(v)))]
504 end
505
506 """
507 last(coll)
508
509 Get the last element of an ordered collection, if it can be computed in O(1) time. This is
510 accomplished by calling [`lastindex`](@ref) to get the last index. Return the end
511 point of an [`AbstractRange`](@ref) even if it is empty.
512
513 See also [`first`](@ref), [`endswith`](@ref).
514
515 # Examples
516 ```jldoctest
517 julia> last(1:2:10)
518 9
519
520 julia> last([1; 2; 3; 4])
521 4
522 ```
523 """
524 last(a) = a[end]
525
526 """
527 last(itr, n::Integer)
528
529 Get the last `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
530 long enough.
531
532 !!! compat "Julia 1.6"
533 This method requires at least Julia 1.6.
534
535 # Examples
536 ```jldoctest
537 julia> last(["foo", "bar", "qux"], 2)
538 2-element Vector{String}:
539 "bar"
540 "qux"
541
542 julia> last(1:6, 10)
543 1:6
544
545 julia> last(Float64[], 1)
546 Float64[]
547 ```
548 """
549 last(itr, n::Integer) = reverse!(collect(Iterators.take(Iterators.reverse(itr), n)))
550 # Faster method for arrays
551 function last(v::AbstractVector, n::Integer)
552 n < 0 && throw(ArgumentError("Number of elements must be nonnegative"))
553 v[range(stop=lastindex(v), length=min(n, checked_length(v)))]
554 end
555
556 """
557 strides(A)
558
559 Return a tuple of the memory strides in each dimension.
560
561 See also: [`stride`](@ref).
562
563 # Examples
564 ```jldoctest
565 julia> A = fill(1, (3,4,5));
566
567 julia> strides(A)
568 (1, 3, 12)
569 ```
570 """
571 function strides end
572
573 """
574 stride(A, k::Integer)
575
576 Return the distance in memory (in number of elements) between adjacent elements in dimension `k`.
577
578 See also: [`strides`](@ref).
579
580 # Examples
581 ```jldoctest
582 julia> A = fill(1, (3,4,5));
583
584 julia> stride(A,2)
585 3
586
587 julia> stride(A,3)
588 12
589 ```
590 """
591 function stride(A::AbstractArray, k::Integer)
592 st = strides(A)
593 k ≤ ndims(A) && return st[k]
594 ndims(A) == 0 && return 1
595 sz = size(A)
596 s = st[1] * sz[1]
597 for i in 2:ndims(A)
598 s += st[i] * sz[i]
599 end
600 return s
601 end
602
603 @inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
604 size_to_strides(s, d) = (s,)
605 size_to_strides(s) = ()
606
607 function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
608 @boundscheck checkbounds(A, I...)
609 return true
610 end
611
612 # used to compute "end" for last index
613 function trailingsize(A, n)
614 s = 1
615 for i=n:ndims(A)
616 s *= size(A,i)
617 end
618 return s
619 end
620 function trailingsize(inds::Indices, n)
621 s = 1
622 for i=n:length(inds)
623 s *= length(inds[i])
624 end
625 return s
626 end
627 # This version is type-stable even if inds is heterogeneous
628 function trailingsize(inds::Indices)
629 @inline
630 prod(map(length, inds))
631 end
632
633 ## Bounds checking ##
634
635 # The overall hierarchy is
636 # `checkbounds(A, I...)` ->
637 # `checkbounds(Bool, A, I...)` ->
638 # `checkbounds_indices(Bool, IA, I)`, which recursively calls
639 # `checkindex` for each dimension
640 #
641 # See the "boundscheck" devdocs for more information.
642 #
643 # Note this hierarchy has been designed to reduce the likelihood of
644 # method ambiguities. We try to make `checkbounds` the place to
645 # specialize on array type, and try to avoid specializations on index
646 # types; conversely, `checkindex` is intended to be specialized only
647 # on index type (especially, its last argument).
648
649 """
650 checkbounds(Bool, A, I...)
651
652 Return `true` if the specified indices `I` are in bounds for the given
653 array `A`. Subtypes of `AbstractArray` should specialize this method
654 if they need to provide custom bounds checking behaviors; however, in
655 many cases one can rely on `A`'s indices and [`checkindex`](@ref).
656
657 See also [`checkindex`](@ref).
658
659 # Examples
660 ```jldoctest
661 julia> A = rand(3, 3);
662
663 julia> checkbounds(Bool, A, 2)
664 true
665
666 julia> checkbounds(Bool, A, 3, 4)
667 false
668
669 julia> checkbounds(Bool, A, 1:3)
670 true
671
672 julia> checkbounds(Bool, A, 1:3, 2:4)
673 false
674 ```
675 """
676 function checkbounds(::Type{Bool}, A::AbstractArray, I...)
677 @inline
678 checkbounds_indices(Bool, axes(A), I)
679 end
680
681 # Linear indexing is explicitly allowed when there is only one (non-cartesian) index
682 function checkbounds(::Type{Bool}, A::AbstractArray, i)
683 @inline
684 checkindex(Bool, eachindex(IndexLinear(), A), i)
685 end
686 # As a special extension, allow using logical arrays that match the source array exactly
687 function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{Bool,N}) where N
688 @inline
689 axes(A) == axes(I)
690 end
691
692 """
693 checkbounds(A, I...)
694
695 Throw an error if the specified indices `I` are not in bounds for the given array `A`.
696 """
697 function checkbounds(A::AbstractArray, I...)
698 @inline
699 checkbounds(Bool, A, I...) || throw_boundserror(A, I)
700 nothing
701 end
702
703 """
704 checkbounds_indices(Bool, IA, I)
705
706 Return `true` if the "requested" indices in the tuple `I` fall within
707 the bounds of the "permitted" indices specified by the tuple
708 `IA`. This function recursively consumes elements of these tuples,
709 usually in a 1-for-1 fashion,
710
711 checkbounds_indices(Bool, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
712 checkbounds_indices(Bool, IA, I)
713
714 Note that [`checkindex`](@ref) is being used to perform the actual
715 bounds-check for a single dimension of the array.
716
717 There are two important exceptions to the 1-1 rule: linear indexing and
718 CartesianIndex{N}, both of which may "consume" more than one element
719 of `IA`.
720
721 See also [`checkbounds`](@ref).
722 """
723 function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
724 @inline
725 checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
726 end
727 function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
728 @inline
729 checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
730 end
731 checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
732 checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
733
734 throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I)))
735
736 # check along a single dimension
737 """
738 checkindex(Bool, inds::AbstractUnitRange, index)
739
740 Return `true` if the given `index` is within the bounds of
741 `inds`. Custom types that would like to behave as indices for all
742 arrays can extend this method in order to provide a specialized bounds
743 checking implementation.
744
745 See also [`checkbounds`](@ref).
746
747 # Examples
748 ```jldoctest
749 julia> checkindex(Bool, 1:20, 8)
750 true
751
752 julia> checkindex(Bool, 1:20, 21)
753 false
754 ```
755 """
756 checkindex(::Type{Bool}, inds::AbstractUnitRange, i) =
757 throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
758 checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
759 checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
760 checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
761 checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
762 checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
763 function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
764 @_propagate_inbounds_meta
765 isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
766 end
767 checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == axes1(I)
768 checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool}) = false
769 function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
770 @inline
771 b = true
772 for i in I
773 b &= checkindex(Bool, inds, i)
774 end
775 b
776 end
777
778 # See also specializations in multidimensional
779
780 ## Constructors ##
781
782 # default arguments to similar()
783 """
784 similar(array, [element_type=eltype(array)], [dims=size(array)])
785
786 Create an uninitialized mutable array with the given element type and size, based upon the
787 given source array. The second and third arguments are both optional, defaulting to the
788 given array's `eltype` and `size`. The dimensions may be specified either as a single tuple
789 argument or as a series of integer arguments.
790
791 Custom AbstractArray subtypes may choose which specific array type is best-suited to return
792 for the given element type and dimensionality. If they do not specialize this method, the
793 default is an `Array{element_type}(undef, dims...)`.
794
795 For example, `similar(1:10, 1, 4)` returns an uninitialized `Array{Int,2}` since ranges are
796 neither mutable nor support 2 dimensions:
797
798 ```julia-repl
799 julia> similar(1:10, 1, 4)
800 1×4 Matrix{Int64}:
801 4419743872 4374413872 4419743888 0
802 ```
803
804 Conversely, `similar(trues(10,10), 2)` returns an uninitialized `BitVector` with two
805 elements since `BitArray`s are both mutable and can support 1-dimensional arrays:
806
807 ```julia-repl
808 julia> similar(trues(10,10), 2)
809 2-element BitVector:
810 0
811 0
812 ```
813
814 Since `BitArray`s can only store elements of type [`Bool`](@ref), however, if you request a
815 different element type it will create a regular `Array` instead:
816
817 ```julia-repl
818 julia> similar(falses(10), Float64, 2, 4)
819 2×4 Matrix{Float64}:
820 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314
821 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314
822 ```
823
824 See also: [`undef`](@ref), [`isassigned`](@ref).
825 """
826 similar(a::AbstractArray{T}) where {T} = similar(a, T)
827 similar(a::AbstractArray, ::Type{T}) where {T} = similar(a, T, to_shape(axes(a)))
828 similar(a::AbstractArray{T}, dims::Tuple) where {T} = similar(a, T, to_shape(dims))
829 similar(a::AbstractArray{T}, dims::DimOrInd...) where {T} = similar(a, T, to_shape(dims))
830 7 (3 %)
7 (3 %) samples spent in similar
7 (100 %) (incl.) when called from #init_jacobian#87 line 322
7 (100 %) samples spent calling similar
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T} = similar(a, T, to_shape(dims))
831 # Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
832 # thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
833 # but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
834 # define this method to convert supported axes to Ints, with the expectation that an offset array
835 # package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
836 similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
837 similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims))
838 # similar creates an Array by default
839 similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N} = Array{T,N}(undef, dims)
840
841 to_shape(::Tuple{}) = ()
842 to_shape(dims::Dims) = dims
843 to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
844 # each dimension
845 to_shape(i::Int) = i
846 to_shape(i::Integer) = Int(i)
847 to_shape(r::OneTo) = Int(last(r))
848 to_shape(r::AbstractUnitRange) = r
849
850 """
851 similar(storagetype, axes)
852
853 Create an uninitialized mutable array analogous to that specified by
854 `storagetype`, but with `axes` specified by the last
855 argument.
856
857 **Examples**:
858
859 similar(Array{Int}, axes(A))
860
861 creates an array that "acts like" an `Array{Int}` (and might indeed be
862 backed by one), but which is indexed identically to `A`. If `A` has
863 conventional indexing, this will be identical to
864 `Array{Int}(undef, size(A))`, but if `A` has unconventional indexing then the
865 indices of the result will match `A`.
866
867 similar(BitArray, (axes(A, 2),))
868
869 would create a 1-dimensional logical array whose indices match those
870 of the columns of `A`.
871 """
872 similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
873 similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
874 similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
875
876 """
877 empty(v::AbstractVector, [eltype])
878
879 Create an empty vector similar to `v`, optionally changing the `eltype`.
880
881 See also: [`empty!`](@ref), [`isempty`](@ref), [`isassigned`](@ref).
882
883 # Examples
884
885 ```jldoctest
886 julia> empty([1.0, 2.0, 3.0])
887 Float64[]
888
889 julia> empty([1.0, 2.0, 3.0], String)
890 String[]
891 ```
892 """
893 empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
894
895 # like empty, but should return a mutable collection, a Vector by default
896 emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
897 emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
898
899 """
900 copy!(dst, src) -> dst
901
902 In-place [`copy`](@ref) of `src` into `dst`, discarding any pre-existing
903 elements in `dst`.
904 If `dst` and `src` are of the same type, `dst == src` should hold after
905 the call. If `dst` and `src` are multidimensional arrays, they must have
906 equal [`axes`](@ref).
907
908 $(_DOCS_ALIASING_WARNING)
909
910 See also [`copyto!`](@ref).
911
912 !!! compat "Julia 1.1"
913 This method requires at least Julia 1.1. In Julia 1.0 this method
914 is available from the `Future` standard library as `Future.copy!`.
915 """
916 function copy!(dst::AbstractVector, src::AbstractVector)
917 firstindex(dst) == firstindex(src) || throw(ArgumentError(
918 "vectors must have the same offset for copy! (consider using `copyto!`)"))
919 if length(dst) != length(src)
920 resize!(dst, length(src))
921 end
922 copyto!(dst, src)
923 end
924
925 function copy!(dst::AbstractArray, src::AbstractArray)
926 axes(dst) == axes(src) || throw(ArgumentError(
927 "arrays must have the same axes for copy! (consider using `copyto!`)"))
928 copyto!(dst, src)
929 end
930
931 ## from general iterable to any array
932
933 # This is `Experimental.@max_methods 1 function copyto! end`, which is not
934 # defined at this point in bootstrap.
935 typeof(function copyto! end).name.max_methods = UInt8(1)
936
937 function copyto!(dest::AbstractArray, src)
938 destiter = eachindex(dest)
939 y = iterate(destiter)
940 for x in src
941 y === nothing &&
942 throw(ArgumentError("destination has fewer elements than required"))
943 dest[y[1]] = x
944 y = iterate(destiter, y[2])
945 end
946 return dest
947 end
948
949 function copyto!(dest::AbstractArray, dstart::Integer, src)
950 i = Int(dstart)
951 if haslength(src) && length(dest) > 0
952 @boundscheck checkbounds(dest, i:(i + length(src) - 1))
953 for x in src
954 @inbounds dest[i] = x
955 i += 1
956 end
957 else
958 for x in src
959 dest[i] = x
960 i += 1
961 end
962 end
963 return dest
964 end
965
966 # copy from an some iterable object into an AbstractArray
967 function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer)
968 if (sstart < 1)
969 throw(ArgumentError(LazyString("source start offset (",sstart,") is < 1")))
970 end
971 y = iterate(src)
972 for j = 1:(sstart-1)
973 if y === nothing
974 throw(ArgumentError(LazyString(
975 "source has fewer elements than required, ",
976 "expected at least ", sstart,", got ", j-1)))
977 end
978 y = iterate(src, y[2])
979 end
980 if y === nothing
981 throw(ArgumentError(LazyString(
982 "source has fewer elements than required, ",
983 "expected at least ",sstart," got ", sstart-1)))
984 end
985 i = Int(dstart)
986 while y !== nothing
987 val, st = y
988 dest[i] = val
989 i += 1
990 y = iterate(src, st)
991 end
992 return dest
993 end
994
995 # this method must be separate from the above since src might not have a length
996 function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
997 n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
998 ", elements, but n should be nonnegative")))
999 n == 0 && return dest
1000 dmax = dstart + n - 1
1001 inds = LinearIndices(dest)
1002 if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
1003 sstart < 1 && throw(ArgumentError(LazyString("source start offset (",
1004 sstart,") is < 1")))
1005 throw(BoundsError(dest, dstart:dmax))
1006 end
1007 y = iterate(src)
1008 for j = 1:(sstart-1)
1009 if y === nothing
1010 throw(ArgumentError(LazyString(
1011 "source has fewer elements than required, ",
1012 "expected at least ",sstart,", got ",j-1)))
1013 end
1014 y = iterate(src, y[2])
1015 end
1016 i = Int(dstart)
1017 while i <= dmax && y !== nothing
1018 val, st = y
1019 @inbounds dest[i] = val
1020 y = iterate(src, st)
1021 i += 1
1022 end
1023 i <= dmax && throw(BoundsError(dest, i))
1024 return dest
1025 end
1026
1027 ## copy between abstract arrays - generally more efficient
1028 ## since a single index variable can be used.
1029
1030 """
1031 copyto!(dest::AbstractArray, src) -> dest
1032
1033 Copy all elements from collection `src` to array `dest`, whose length must be greater than
1034 or equal to the length `n` of `src`. The first `n` elements of `dest` are overwritten,
1035 the other elements are left untouched.
1036
1037 See also [`copy!`](@ref Base.copy!), [`copy`](@ref).
1038
1039 # Examples
1040 ```jldoctest
1041 julia> x = [1., 0., 3., 0., 5.];
1042
1043 julia> y = zeros(7);
1044
1045 julia> copyto!(y, x);
1046
1047 julia> y
1048 7-element Vector{Float64}:
1049 1.0
1050 0.0
1051 3.0
1052 0.0
1053 5.0
1054 0.0
1055 0.0
1056 ```
1057 """
1058 function copyto!(dest::AbstractArray, src::AbstractArray)
1059 isempty(src) && return dest
1060 if dest isa BitArray
1061 # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1062 return _copyto_bitarray!(dest, src)
1063 end
1064 src′ = unalias(dest, src)
1065 29 (11 %)
29 (11 %) samples spent in copyto!
29 (100 %) (incl.) when called from copy_similar line 416
29 (100 %) samples spent calling copyto_unaliased!
copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
1066 end
1067
1068 function copyto!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
1069 isempty(src) && return dest
1070 src′ = unalias(dest, src)
1071 copyto_unaliased!(deststyle, dest, srcstyle, src′)
1072 end
1073
1074
29 (11 %) samples spent in copyto_unaliased!
29 (100 %) (incl.) when called from copyto! line 1065
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
1075 isempty(src) && return dest
1076 destinds, srcinds = LinearIndices(dest), LinearIndices(src)
1077 idf, isf = first(destinds), first(srcinds)
1078 Δi = idf - isf
1079 (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
1080 throw(BoundsError(dest, srcinds))
1081 if deststyle isa IndexLinear
1082 if srcstyle isa IndexLinear
1083 # Single-index implementation
1084 @inbounds for i in srcinds
1085 dest[i + Δi] = src[i]
1086 end
1087 else
1088 # Dual-index implementation
1089 i = idf - 1
1090 8 (3 %)
8 (100 %) samples spent calling iterate
@inbounds for a in src
1091 20 (7 %)
20 (100 %) samples spent calling setindex!
dest[i+=1] = a
1092 1 (0 %)
1 (100 %) samples spent calling iterate
end
1093 end
1094 else
1095 iterdest, itersrc = eachindex(dest), eachindex(src)
1096 if iterdest == itersrc
1097 # Shared-iterator implementation
1098 for I in iterdest
1099 @inbounds dest[I] = src[I]
1100 end
1101 else
1102 # Dual-iterator implementation
1103 ret = iterate(iterdest)
1104 @inbounds for a in src
1105 idx, state = ret::NTuple{2,Any}
1106 dest[idx] = a
1107 ret = iterate(iterdest, state)
1108 end
1109 end
1110 end
1111 return dest
1112 end
1113
1114 function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
1115 copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
1116 end
1117
1118 function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray, sstart::Integer)
1119 srcinds = LinearIndices(src)
1120 checkbounds(Bool, srcinds, sstart) || throw(BoundsError(src, sstart))
1121 copyto!(dest, dstart, src, sstart, last(srcinds)-sstart+1)
1122 end
1123
1124 function copyto!(dest::AbstractArray, dstart::Integer,
1125 src::AbstractArray, sstart::Integer,
1126 n::Integer)
1127 n == 0 && return dest
1128 n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
1129 n," elements, but n should be nonnegative")))
1130 destinds, srcinds = LinearIndices(dest), LinearIndices(src)
1131 (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
1132 (checkbounds(Bool, srcinds, sstart) && checkbounds(Bool, srcinds, sstart+n-1)) || throw(BoundsError(src, sstart:sstart+n-1))
1133 src′ = unalias(dest, src)
1134 @inbounds for i = 0:n-1
1135 dest[dstart+i] = src′[sstart+i]
1136 end
1137 return dest
1138 end
1139
1140 function copy(a::AbstractArray)
1141 @_propagate_inbounds_meta
1142 copymutable(a)
1143 end
1144
1145 function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
1146 A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1147 if length(ir_dest) != length(ir_src)
1148 throw(ArgumentError(LazyString("source and destination must have same size (got ",
1149 length(ir_src)," and ",length(ir_dest),")")))
1150 end
1151 if length(jr_dest) != length(jr_src)
1152 throw(ArgumentError(LazyString("source and destination must have same size (got ",
1153 length(jr_src)," and ",length(jr_dest),")")))
1154 end
1155 @boundscheck checkbounds(B, ir_dest, jr_dest)
1156 @boundscheck checkbounds(A, ir_src, jr_src)
1157 A′ = unalias(B, A)
1158 jdest = first(jr_dest)
1159 for jsrc in jr_src
1160 idest = first(ir_dest)
1161 for isrc in ir_src
1162 @inbounds B[idest,jdest] = A′[isrc,jsrc]
1163 idest += step(ir_dest)
1164 end
1165 jdest += step(jr_dest)
1166 end
1167 return B
1168 end
1169
1170 @noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
1171
1172 function copyto_axcheck!(dest, src)
1173 _checkaxs(axes(dest), axes(src))
1174 copyto!(dest, src)
1175 end
1176
1177 """
1178 copymutable(a)
1179
1180 Make a mutable copy of an array or iterable `a`. For `a::Array`,
1181 this is equivalent to `copy(a)`, but for other array types it may
1182 differ depending on the type of `similar(a)`. For generic iterables
1183 this is equivalent to `collect(a)`.
1184
1185 # Examples
1186 ```jldoctest
1187 julia> tup = (1, 2, 3)
1188 (1, 2, 3)
1189
1190 julia> Base.copymutable(tup)
1191 3-element Vector{Int64}:
1192 1
1193 2
1194 3
1195 ```
1196 """
1197 function copymutable(a::AbstractArray)
1198 @_propagate_inbounds_meta
1199 copyto!(similar(a), a)
1200 end
1201 copymutable(itr) = collect(itr)
1202
1203 zero(x::AbstractArray{T}) where {T} = fill!(similar(x, typeof(zero(T))), zero(T))
1204
1205 ## iteration support for arrays by iterating over `eachindex` in the array ##
1206 # Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1207
1208 # While the definitions for IndexLinear are all simple enough to inline on their
1209 # own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1210 # inlining.
1211 function iterate(A::AbstractArray, state=(eachindex(A),))
1212 17 (6 %)
17 (6 %) samples spent in iterate
8 (47 %) (incl.) when called from iterate line 1212
8 (47 %) (incl.) when called from copyto_unaliased! line 1090
1 (6 %) (incl.) when called from copyto_unaliased! line 1092
8 (47 %) samples spent calling iterate
8 (47 %) samples spent calling iterate
1 (6 %) samples spent calling iterate
y = iterate(state...)
1213 y === nothing && return nothing
1214 A[y[1]], (state[1], tail(y)...)
1215 end
1216
1217 isempty(a::AbstractArray) = (length(a) == 0)
1218
1219
1220 ## range conversions ##
1221
1222 map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
1223 map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
1224 map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
1225 function map(::Type{T}, r::LinRange) where T<:AbstractFloat
1226 LinRange(T(r.start), T(r.stop), length(r))
1227 end
1228
1229 ## unsafe/pointer conversions ##
1230
1231 # note: the following type definitions don't mean any AbstractArray is convertible to
1232 # a data Ref. they just map the array element type to the pointer type for
1233 # convenience in cases that work.
1234 pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
1235 function pointer(x::AbstractArray{T}, i::Integer) where T
1236 @inline
1237 unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
1238 end
1239
1240 # The distance from pointer(x) to the element at x[I...] in bytes
1241 _memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
1242 function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
1243 J = _to_subscript_indices(x, I...)
1244 return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
1245 end
1246
1247 ## Approach:
1248 # We only define one fallback method on getindex for all argument types.
1249 # That dispatches to an (inlined) internal _getindex function, where the goal is
1250 # to transform the indices such that we can call the only getindex method that
1251 # we require the type A{T,N} <: AbstractArray{T,N} to define; either:
1252 # getindex(::A, ::Int) # if IndexStyle(A) == IndexLinear() OR
1253 # getindex(::A{T,N}, ::Vararg{Int, N}) where {T,N} # if IndexCartesian()
1254 # If the subtype hasn't defined the required method, it falls back to the
1255 # _getindex function again where an error is thrown to prevent stack overflows.
1256 """
1257 getindex(A, inds...)
1258
1259 Return a subset of array `A` as specified by `inds`, where each `ind` may be,
1260 for example, an `Int`, an [`AbstractRange`](@ref), or a [`Vector`](@ref).
1261 See the manual section on [array indexing](@ref man-array-indexing) for details.
1262
1263 # Examples
1264 ```jldoctest
1265 julia> A = [1 2; 3 4]
1266 2×2 Matrix{Int64}:
1267 1 2
1268 3 4
1269
1270 julia> getindex(A, 1)
1271 1
1272
1273 julia> getindex(A, [2, 1])
1274 2-element Vector{Int64}:
1275 3
1276 1
1277
1278 julia> getindex(A, 2:4)
1279 3-element Vector{Int64}:
1280 3
1281 2
1282 4
1283 ```
1284 """
1285 function getindex(A::AbstractArray, I...)
1286 @_propagate_inbounds_meta
1287 error_if_canonical_getindex(IndexStyle(A), A, I...)
1288 _getindex(IndexStyle(A), A, to_indices(A, I)...)
1289 end
1290 # To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1291 @propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
1292
1293 function unsafe_getindex(A::AbstractArray, I...)
1294 @inline
1295 @inbounds r = getindex(A, I...)
1296 r
1297 end
1298
1299 struct CanonicalIndexError <: Exception
1300 func::String
1301 type::Any
1302 CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
1303 end
1304
1305 error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
1306 throw(CanonicalIndexError("getindex", typeof(A)))
1307 error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
1308 throw(CanonicalIndexError("getindex", typeof(A)))
1309 error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
1310
1311 ## Internal definitions
1312 _getindex(::IndexStyle, A::AbstractArray, I...) =
1313 error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1314
1315 ## IndexLinear Scalar indexing: canonical method is one Int
1316 _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)
1317 _getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
1318 function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
1319 @inline
1320 @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
1321 @inbounds r = getindex(A, _to_linear_index(A, I...))
1322 r
1323 end
1324 _to_linear_index(A::AbstractArray, i::Integer) = i
1325 _to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1326 _to_linear_index(A::AbstractArray) = first(LinearIndices(A))
1327 _to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
1328
1329 ## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1330 function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
1331 @inline
1332 @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
1333 @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
1334 r
1335 end
1336 function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
1337 @_propagate_inbounds_meta
1338 getindex(A, I...)
1339 end
1340 _to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
1341 _to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
1342 _to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
1343 _to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
1344 _to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
1345 function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1346 @inline
1347 J, Jrem = IteratorsMD.split(I, Val(N))
1348 _to_subscript_indices(A, J, Jrem)
1349 end
1350 _to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
1351 __to_subscript_indices(A, axes(A), J, Jrem)
1352 function __to_subscript_indices(A::AbstractArray,
1353 ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1354 @inline
1355 (J..., map(first, tail(_remaining_size(J, axes(A))))...)
1356 end
1357 _to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
1358 _to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
1359 _remaining_size(::Tuple{Any}, t::Tuple) = t
1360 _remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
1361 _unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
1362 _unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
1363
1364 ## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1365 # function that allows dispatch on array storage
1366
1367 """
1368 setindex!(A, X, inds...)
1369 A[inds...] = X
1370
1371 Store values from array `X` within some subset of `A` as specified by `inds`.
1372 The syntax `A[inds...] = X` is equivalent to `(setindex!(A, X, inds...); X)`.
1373
1374 $(_DOCS_ALIASING_WARNING)
1375
1376 # Examples
1377 ```jldoctest
1378 julia> A = zeros(2,2);
1379
1380 julia> setindex!(A, [10, 20], [1, 2]);
1381
1382 julia> A[[3, 4]] = [30, 40];
1383
1384 julia> A
1385 2×2 Matrix{Float64}:
1386 10.0 30.0
1387 20.0 40.0
1388 ```
1389 """
1390 function setindex!(A::AbstractArray, v, I...)
1391 @_propagate_inbounds_meta
1392 error_if_canonical_setindex(IndexStyle(A), A, I...)
1393 26 (10 %)
26 (10 %) samples spent in setindex!
26 (100 %) (incl.) when called from macro expansion line 1004
26 (100 %) samples spent calling _setindex!
_setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
1394 end
1395 function unsafe_setindex!(A::AbstractArray, v, I...)
1396 @inline
1397 @inbounds r = setindex!(A, v, I...)
1398 r
1399 end
1400
1401 error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
1402 throw(CanonicalIndexError("setindex!", typeof(A)))
1403 error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
1404 throw(CanonicalIndexError("setindex!", typeof(A)))
1405 error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
1406
1407 ## Internal definitions
1408 _setindex!(::IndexStyle, A::AbstractArray, v, I...) =
1409 error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1410
1411 ## IndexLinear Scalar indexing
1412 _setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
1413 function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
1414 @inline
1415 @boundscheck checkbounds(A, I...)
1416 26 (10 %)
26 (10 %) samples spent in _setindex!
26 (100 %) (incl.) when called from setindex! line 1393
26 (100 %) samples spent calling setindex!
@inbounds r = setindex!(A, v, _to_linear_index(A, I...))
1417 r
1418 end
1419
1420 # IndexCartesian Scalar indexing
1421 function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
1422 @_propagate_inbounds_meta
1423 setindex!(A, v, I...)
1424 end
1425 function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
1426 @inline
1427 @boundscheck checkbounds(A, I...)
1428 @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
1429 r
1430 end
1431
1432 """
1433 parent(A)
1434
1435 Return the underlying parent object of the view. This parent of objects of types `SubArray`, `SubString`, `ReshapedArray`
1436 or `LinearAlgebra.Transpose` is what was passed as an argument to `view`, `reshape`, `transpose`, etc.
1437 during object creation. If the input is not a wrapped object, return the input itself. If the input is
1438 wrapped multiple times, only the outermost wrapper will be removed.
1439
1440 # Examples
1441 ```jldoctest
1442 julia> A = [1 2; 3 4]
1443 2×2 Matrix{Int64}:
1444 1 2
1445 3 4
1446
1447 julia> V = view(A, 1:2, :)
1448 2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1449 1 2
1450 3 4
1451
1452 julia> parent(V)
1453 2×2 Matrix{Int64}:
1454 1 2
1455 3 4
1456 ```
1457 """
1458 function parent end
1459
1460 parent(a::AbstractArray) = a
1461
1462 ## rudimentary aliasing detection ##
1463 """
1464 Base.unalias(dest, A)
1465
1466 Return either `A` or a copy of `A` in a rough effort to prevent modifications to `dest` from
1467 affecting the returned object. No guarantees are provided.
1468
1469 Custom arrays that wrap or use fields containing arrays that might alias against other
1470 external objects should provide a [`Base.dataids`](@ref) implementation.
1471
1472 This function must return an object of exactly the same type as `A` for performance and type
1473 stability. Mutable custom arrays for which [`copy(A)`](@ref) is not `typeof(A)` should
1474 provide a [`Base.unaliascopy`](@ref) implementation.
1475
1476 See also [`Base.mightalias`](@ref).
1477 """
1478 unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
1479 unalias(dest, A::AbstractRange) = A
1480 unalias(dest, A) = A
1481
1482 """
1483 Base.unaliascopy(A)
1484
1485 Make a preventative copy of `A` in an operation where `A` [`Base.mightalias`](@ref) against
1486 another array in order to preserve consistent semantics as that other array is mutated.
1487
1488 This must return an object of the same type as `A` to preserve optimal performance in the
1489 much more common case where aliasing does not occur. By default,
1490 `unaliascopy(A::AbstractArray)` will attempt to use [`copy(A)`](@ref), but in cases where
1491 `copy(A)` is not a `typeof(A)`, then the array should provide a custom implementation of
1492 `Base.unaliascopy(A)`.
1493 """
1494 unaliascopy(A::Array) = copy(A)
1495 unaliascopy(A::AbstractArray)::typeof(A) = (@noinline; _unaliascopy(A, copy(A)))
1496 _unaliascopy(A::T, C::T) where {T} = C
1497 _unaliascopy(A, C) = throw(ArgumentError("""
1498 an array of type `$(typename(typeof(A)).wrapper)` shares memory with another argument
1499 and must make a preventative copy of itself in order to maintain consistent semantics,
1500 but `copy(::$(typeof(A)))` returns a new array of type `$(typeof(C))`.
1501 To fix, implement:
1502 `Base.unaliascopy(A::$(typename(typeof(A)).wrapper))::typeof(A)`"""))
1503 unaliascopy(A) = A
1504
1505 """
1506 Base.mightalias(A::AbstractArray, B::AbstractArray)
1507
1508 Perform a conservative test to check if arrays `A` and `B` might share the same memory.
1509
1510 By default, this simply checks if either of the arrays reference the same memory
1511 regions, as identified by their [`Base.dataids`](@ref).
1512 """
1513 mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !_isdisjoint(dataids(A), dataids(B))
1514 mightalias(x, y) = false
1515
1516 _isdisjoint(as::Tuple{}, bs::Tuple{}) = true
1517 _isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
1518 _isdisjoint(as::Tuple{}, bs::Tuple) = true
1519 _isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
1520 _isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
1521 _isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
1522 _isdisjoint(as::Tuple, bs::Tuple{}) = true
1523 _isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
1524 _isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
1525
1526 """
1527 Base.dataids(A::AbstractArray)
1528
1529 Return a tuple of `UInt`s that represent the mutable data segments of an array.
1530
1531 Custom arrays that would like to opt-in to aliasing detection of their component
1532 parts can specialize this method to return the concatenation of the `dataids` of
1533 their component parts. A typical definition for an array that wraps a parent is
1534 `Base.dataids(C::CustomArray) = dataids(C.parent)`.
1535 """
1536 dataids(A::AbstractArray) = (UInt(objectid(A)),)
1537 dataids(A::Array) = (UInt(pointer(A)),)
1538 dataids(::AbstractRange) = ()
1539 dataids(x) = ()
1540
1541 ## get (getindex with a default value) ##
1542
1543 RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1544 AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1545
1546 get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
1547 get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
1548 get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
1549 get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
1550 get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
1551 get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
1552
1553 function get!(X::AbstractVector{T}, A::AbstractVector, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
1554 # 1d is not linear indexing
1555 ind = findall(in(axes1(A)), I)
1556 X[ind] = A[I[ind]]
1557 Xind = axes1(X)
1558 X[first(Xind):first(ind)-1] = default
1559 X[last(ind)+1:last(Xind)] = default
1560 X
1561 end
1562 function get!(X::AbstractArray{T}, A::AbstractArray, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
1563 # Linear indexing
1564 ind = findall(in(1:length(A)), I)
1565 X[ind] = A[I[ind]]
1566 fill!(view(X, 1:first(ind)-1), default)
1567 fill!(view(X, last(ind)+1:length(X)), default)
1568 X
1569 end
1570
1571 get(A::AbstractArray, I::AbstractRange, default) = get!(similar(A, typeof(default), index_shape(I)), A, I, default)
1572
1573 function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
1574 fill!(X, default)
1575 dst, src = indcopy(size(A), I)
1576 X[dst...] = A[src...]
1577 X
1578 end
1579
1580 get(A::AbstractArray, I::RangeVecIntList, default) =
1581 get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1582
1583 ## structured matrix methods ##
1584 replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
1585 replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
1586
1587 ## Concatenation ##
1588 eltypeof(x) = typeof(x)
1589 eltypeof(x::AbstractArray) = eltype(x)
1590
1591 promote_eltypeof() = error()
1592 promote_eltypeof(v1) = eltypeof(v1)
1593 promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
1594 promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
1595 promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
1596
1597 promote_eltype() = error()
1598 promote_eltype(v1) = eltype(v1)
1599 promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
1600 promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
1601 promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
1602
1603 #TODO: ERROR CHECK
1604 _cat(catdim::Int) = Vector{Any}()
1605
1606 typed_vcat(::Type{T}) where {T} = Vector{T}()
1607 typed_hcat(::Type{T}) where {T} = Vector{T}()
1608
1609 ## cat: special cases
1610 vcat(X::T...) where {T} = T[ X[i] for i=1:length(X) ]
1611 vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
1612 hcat(X::T...) where {T} = T[ X[j] for i=1:1, j=1:length(X) ]
1613 hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
1614
1615 vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
1616 hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
1617 typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
1618 typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
1619
1620 vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
1621 vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
1622
1623 # FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1624 # and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1625 # but that solution currently fails (see #27188 and #27224)
1626 AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1627
1628 _typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
1629 _typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
1630 _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1631
1632 function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
1633 pos = 1
1634 for k=1:Int(length(V))::Int
1635 Vk = V[k]
1636 p1 = pos + Int(length(Vk))::Int - 1
1637 a[pos:p1] = Vk
1638 pos = p1+1
1639 end
1640 a
1641 end
1642
1643 typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
1644
1645 # Catch indexing errors like v[i +1] (instead of v[i+1] or v[i + 1]), where indexing is
1646 # interpreted as a typed concatenation. (issue #49676)
1647 typed_hcat(::AbstractArray, other...) = throw(ArgumentError("It is unclear whether you \
1648 intend to perform an indexing operation or typed concatenation. If you intend to \
1649 perform indexing (v[1 + 2]), adjust spacing or insert missing operator to clarify. \
1650 If you intend to perform typed concatenation (T[1 2]), ensure that T is a type."))
1651
1652
1653 hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
1654 hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
1655
1656 function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1657 nargs = length(A)
1658 nrows = size(A[1], 1)
1659 ncols = 0
1660 dense = true
1661 for j = 1:nargs
1662 Aj = A[j]
1663 if size(Aj, 1) != nrows
1664 throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
1665 end
1666 dense &= isa(Aj,Array)
1667 nd = ndims(Aj)
1668 ncols += (nd==2 ? size(Aj,2) : 1)
1669 end
1670 B = similar(A[1], T, nrows, ncols)
1671 pos = 1
1672 if dense
1673 for k=1:nargs
1674 Ak = A[k]
1675 n = length(Ak)
1676 copyto!(B, pos, Ak, 1, n)
1677 pos += n
1678 end
1679 else
1680 for k=1:nargs
1681 Ak = A[k]
1682 p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
1683 B[:, pos:p1] = Ak
1684 pos = p1+1
1685 end
1686 end
1687 return B
1688 end
1689
1690 vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
1691 vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
1692
1693 function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1694 nargs = length(A)
1695 nrows = sum(a->size(a, 1), A)::Int
1696 ncols = size(A[1], 2)
1697 for j = 2:nargs
1698 if size(A[j], 2) != ncols
1699 throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
1700 end
1701 end
1702 B = similar(A[1], T, nrows, ncols)
1703 pos = 1
1704 for k=1:nargs
1705 Ak = A[k]
1706 p1 = pos+size(Ak,1)::Int-1
1707 B[pos:p1, :] = Ak
1708 pos = p1+1
1709 end
1710 return B
1711 end
1712
1713 typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
1714
1715 reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
1716 _typed_vcat(mapreduce(eltype, promote_type, A), A)
1717
1718 reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
1719 _typed_hcat(mapreduce(eltype, promote_type, A), A)
1720
1721 ## cat: general case
1722
1723 # helper functions
1724 cat_size(A) = (1,)
1725 cat_size(A::AbstractArray) = size(A)
1726 cat_size(A, d) = 1
1727 cat_size(A::AbstractArray, d) = size(A, d)
1728
1729 cat_length(::Any) = 1
1730 cat_length(a::AbstractArray) = length(a)
1731
1732 cat_ndims(a) = 0
1733 cat_ndims(a::AbstractArray) = ndims(a)
1734
1735 cat_indices(A, d) = OneTo(1)
1736 cat_indices(A::AbstractArray, d) = axes(A, d)
1737
1738 cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1739 cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
1740 cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1741 cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
1742 cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
1743 cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
1744
1745 # These are for backwards compatibility (even though internal)
1746 cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
1747 function cat_shape(dims, shapes::Tuple)
1748 out_shape = ()
1749 for s in shapes
1750 out_shape = _cshp(1, dims, out_shape, s)
1751 end
1752 return out_shape
1753 end
1754 # The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1755 cat_size_shape(dims) = ntuple(zero, Val(length(dims)))
1756 @inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
1757 _cat_size_shape(dims, shape) = shape
1758 @inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
1759
1760 _cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
1761 _cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
1762 _cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
1763 @inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
1764 (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1765 @inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
1766 (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1767 @inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
1768 _cs(ndim, shape[1], 1)
1769 (1, _cshp(ndim + 1, (), tail(shape), ())...)
1770 end
1771 @inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
1772 next = _cs(ndim, shape[1], nshape[1])
1773 (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
1774 end
1775 @inline function _cshp(ndim::Int, dims, shape, nshape)
1776 a = shape[1]
1777 b = nshape[1]
1778 next = dims[1] ? a + b : _cs(ndim, a, b)
1779 (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
1780 end
1781
1782 _cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1783 "mismatch in dimension $d (expected $a got $b)")))
1784
1785 dims2cat(::Val{dims}) where dims = dims2cat(dims)
1786 function dims2cat(dims)
1787 if any(≤(0), dims)
1788 throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
1789 end
1790 ntuple(in(dims), maximum(dims))
1791 end
1792
1793 _cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
1794
1795 @inline function _cat_t(dims, ::Type{T}, X...) where {T}
1796 catdims = dims2cat(dims)
1797 shape = cat_size_shape(catdims, X...)
1798 A = cat_similar(X[1], T, shape)
1799 if count(!iszero, catdims)::Int > 1
1800 fill!(A, zero(T))
1801 end
1802 return __cat(A, shape, catdims, X...)
1803 end
1804 # this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1805 # nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1806 @inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
1807
1808 # Why isn't this called `__cat!`?
1809 __cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
1810
1811 function __cat_offset!(A, shape, catdims, offsets, x, X...)
1812 # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1813 newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
1814 return __cat_offset!(A, shape, catdims, newoffsets, X...)
1815 end
1816 __cat_offset!(A, shape, catdims, offsets) = A
1817
1818 function __cat_offset1!(A, shape, catdims, offsets, x)
1819 inds = ntuple(length(offsets)) do i
1820 (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
1821 end
1822 _copy_or_fill!(A, inds, x)
1823 newoffsets = ntuple(length(offsets)) do i
1824 (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
1825 end
1826 return newoffsets
1827 end
1828
1829 _copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
1830 _copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
1831
1832 """
1833 vcat(A...)
1834
1835 Concatenate arrays or numbers vertically. Equivalent to [`cat`](@ref)`(A...; dims=1)`,
1836 and to the syntax `[a; b; c]`.
1837
1838 To concatenate a large vector of arrays, `reduce(vcat, A)` calls an efficient method
1839 when `A isa AbstractVector{<:AbstractVecOrMat}`, rather than working pairwise.
1840
1841 See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1842
1843 # Examples
1844 ```jldoctest
1845 julia> v = vcat([1,2], [3,4])
1846 4-element Vector{Int64}:
1847 1
1848 2
1849 3
1850 4
1851
1852 julia> v == vcat(1, 2, [3,4]) # accepts numbers
1853 true
1854
1855 julia> v == [1; 2; [3,4]] # syntax for the same operation
1856 true
1857
1858 julia> summary(ComplexF64[1; 2; [3,4]]) # syntax for supplying the element type
1859 "4-element Vector{ComplexF64}"
1860
1861 julia> vcat(range(1, 2, length=3)) # collects lazy ranges
1862 3-element Vector{Float64}:
1863 1.0
1864 1.5
1865 2.0
1866
1867 julia> two = ([10, 20, 30]', Float64[4 5 6; 7 8 9]) # row vector and a matrix
1868 ([10 20 30], [4.0 5.0 6.0; 7.0 8.0 9.0])
1869
1870 julia> vcat(two...)
1871 3×3 Matrix{Float64}:
1872 10.0 20.0 30.0
1873 4.0 5.0 6.0
1874 7.0 8.0 9.0
1875
1876 julia> vs = [[1, 2], [3, 4], [5, 6]];
1877
1878 julia> reduce(vcat, vs) # more efficient than vcat(vs...)
1879 6-element Vector{Int64}:
1880 1
1881 2
1882 3
1883 4
1884 5
1885 6
1886
1887 julia> ans == collect(Iterators.flatten(vs))
1888 true
1889 ```
1890 """
1891 vcat(X...) = cat(X...; dims=Val(1))
1892 """
1893 hcat(A...)
1894
1895 Concatenate arrays or numbers horizontally. Equivalent to [`cat`](@ref)`(A...; dims=2)`,
1896 and to the syntax `[a b c]` or `[a;; b;; c]`.
1897
1898 For a large vector of arrays, `reduce(hcat, A)` calls an efficient method
1899 when `A isa AbstractVector{<:AbstractVecOrMat}`.
1900 For a vector of vectors, this can also be written [`stack`](@ref)`(A)`.
1901
1902 See also [`vcat`](@ref), [`hvcat`](@ref).
1903
1904 # Examples
1905 ```jldoctest
1906 julia> hcat([1,2], [3,4], [5,6])
1907 2×3 Matrix{Int64}:
1908 1 3 5
1909 2 4 6
1910
1911 julia> hcat(1, 2, [30 40], [5, 6, 7]') # accepts numbers
1912 1×7 Matrix{Int64}:
1913 1 2 30 40 5 6 7
1914
1915 julia> ans == [1 2 [30 40] [5, 6, 7]'] # syntax for the same operation
1916 true
1917
1918 julia> Float32[1 2 [30 40] [5, 6, 7]'] # syntax for supplying the eltype
1919 1×7 Matrix{Float32}:
1920 1.0 2.0 30.0 40.0 5.0 6.0 7.0
1921
1922 julia> ms = [zeros(2,2), [1 2; 3 4], [50 60; 70 80]];
1923
1924 julia> reduce(hcat, ms) # more efficient than hcat(ms...)
1925 2×6 Matrix{Float64}:
1926 0.0 0.0 1.0 2.0 50.0 60.0
1927 0.0 0.0 3.0 4.0 70.0 80.0
1928
1929 julia> stack(ms) |> summary # disagrees on a vector of matrices
1930 "2×2×3 Array{Float64, 3}"
1931
1932 julia> hcat(Int[], Int[], Int[]) # empty vectors, each of size (0,)
1933 0×3 Matrix{Int64}
1934
1935 julia> hcat([1.1, 9.9], Matrix(undef, 2, 0)) # hcat with empty 2×0 Matrix
1936 2×1 Matrix{Any}:
1937 1.1
1938 9.9
1939 ```
1940 """
1941 hcat(X...) = cat(X...; dims=Val(2))
1942
1943 typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
1944 typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
1945
1946 """
1947 cat(A...; dims)
1948
1949 Concatenate the input arrays along the dimensions specified in `dims`.
1950
1951 Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
1952 a in A)`.
1953 Along other dimensions, all input arrays should have the same size,
1954 which will also be the size of the output array along those dimensions.
1955
1956 If `dims` is a single number, the different arrays are tightly packed along that dimension.
1957 If `dims` is an iterable containing several dimensions, the positions along these dimensions
1958 are increased simultaneously for each input array, filling with zero elsewhere.
1959 This allows one to construct block-diagonal matrices as `cat(matrices...; dims=(1,2))`,
1960 and their higher-dimensional analogues.
1961
1962 The special case `dims=1` is [`vcat`](@ref), and `dims=2` is [`hcat`](@ref).
1963 See also [`hvcat`](@ref), [`hvncat`](@ref), [`stack`](@ref), [`repeat`](@ref).
1964
1965 The keyword also accepts `Val(dims)`.
1966
1967 !!! compat "Julia 1.8"
1968 For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
1969
1970 # Examples
1971 ```jldoctest
1972 julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2) # same as hcat
1973 2×6×1 Array{Float64, 3}:
1974 [:, :, 1] =
1975 1.0 2.0 3.14159 10.0 10.0 10.0
1976 3.0 4.0 3.14159 10.0 10.0 10.0
1977
1978 julia> cat(true, trues(2,2), trues(4)', dims=(1,2)) # block-diagonal
1979 4×7 Matrix{Bool}:
1980 1 0 0 0 0 0 0
1981 0 1 1 0 0 0 0
1982 0 1 1 0 0 0 0
1983 0 0 0 1 1 1 1
1984
1985 julia> cat(1, [2], [3;;]; dims=Val(2))
1986 1×3 Matrix{Int64}:
1987 1 2 3
1988 ```
1989 """
1990 @inline cat(A...; dims) = _cat(dims, A...)
1991 # `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
1992 @constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
1993
1994 # The specializations for 1 and 2 inputs are important
1995 # especially when running with --inline=no, see #11158
1996 vcat(A::AbstractArray) = cat(A; dims=Val(1))
1997 vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
1998 vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
1999 vcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(1))
2000 hcat(A::AbstractArray) = cat(A; dims=Val(2))
2001 hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
2002 hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
2003 hcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(2))
2004
2005 typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
2006 typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
2007 typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
2008 typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
2009 typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2010 typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2011
2012 # 2d horizontal and vertical concatenation
2013
2014 # these are produced in lowering if splatting occurs inside hvcat
2015 hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
2016 typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
2017
2018 function hvcat(nbc::Int, as...)
2019 # nbc = # of block columns
2020 n = length(as)
2021 mod(n,nbc) != 0 &&
2022 throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
2023 nbr = div(n,nbc)
2024 hvcat(ntuple(Returns(nbc), nbr), as...)
2025 end
2026
2027 """
2028 hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2029
2030 Horizontal and vertical concatenation in one call. This function is called for block matrix
2031 syntax. The first argument specifies the number of arguments to concatenate in each block
2032 row. If the first argument is a single integer `n`, then all block rows are assumed to have `n`
2033 block columns.
2034
2035 # Examples
2036 ```jldoctest
2037 julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2038 (1, 2, 3, 4, 5, 6)
2039
2040 julia> [a b c; d e f]
2041 2×3 Matrix{Int64}:
2042 1 2 3
2043 4 5 6
2044
2045 julia> hvcat((3,3), a,b,c,d,e,f)
2046 2×3 Matrix{Int64}:
2047 1 2 3
2048 4 5 6
2049
2050 julia> [a b; c d; e f]
2051 3×2 Matrix{Int64}:
2052 1 2
2053 3 4
2054 5 6
2055
2056 julia> hvcat((2,2,2), a,b,c,d,e,f)
2057 3×2 Matrix{Int64}:
2058 1 2
2059 3 4
2060 5 6
2061 julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f)
2062 true
2063 ```
2064 """
2065 hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
2066 hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray{T}...) where {T} = typed_hvcat(T, rows, xs...)
2067
2068 function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T
2069 nbr = length(rows) # number of block rows
2070
2071 nc = 0
2072 for i=1:rows[1]
2073 nc += size(as[i],2)
2074 end
2075
2076 nr = 0
2077 a = 1
2078 for i = 1:nbr
2079 nr += size(as[a],1)
2080 a += rows[i]
2081 end
2082
2083 out = similar(as[1], T, nr, nc)
2084
2085 a = 1
2086 r = 1
2087 for i = 1:nbr
2088 c = 1
2089 szi = size(as[a],1)
2090 for j = 1:rows[i]
2091 Aj = as[a+j-1]
2092 szj = size(Aj,2)
2093 if size(Aj,1) != szi
2094 throw(DimensionMismatch("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
2095 end
2096 if c-1+szj > nc
2097 throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
2098 end
2099 out[r:r-1+szi, c:c-1+szj] = Aj
2100 c += szj
2101 end
2102 if c != nc+1
2103 throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
2104 end
2105 r += szi
2106 a += rows[i]
2107 end
2108 out
2109 end
2110
2111 hvcat(rows::Tuple{Vararg{Int}}) = []
2112 typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
2113
2114 function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
2115 nr = length(rows)
2116 nc = rows[1]
2117
2118 a = Matrix{T}(undef, nr, nc)
2119 if length(a) != length(xs)
2120 throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2121 end
2122 k = 1
2123 @inbounds for i=1:nr
2124 if nc != rows[i]
2125 throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2126 end
2127 for j=1:nc
2128 a[i,j] = xs[k]
2129 k += 1
2130 end
2131 end
2132 a
2133 end
2134
2135 function hvcat_fill!(a::Array, xs::Tuple)
2136 nr, nc = size(a,1), size(a,2)
2137 len = length(xs)
2138 if nr*nc != len
2139 throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
2140 end
2141 k = 1
2142 for i=1:nr
2143 @inbounds for j=1:nc
2144 a[i,j] = xs[k]
2145 k += 1
2146 end
2147 end
2148 a
2149 end
2150
2151 hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
2152 hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
2153 # the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2154 hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
2155
2156 function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
2157 nr = length(rows)
2158 nc = rows[1]
2159 for i = 2:nr
2160 if nc != rows[i]
2161 throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2162 end
2163 end
2164 hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
2165 end
2166
2167 function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T
2168 nbr = length(rows) # number of block rows
2169 rs = Vector{Any}(undef, nbr)
2170 a = 1
2171 for i = 1:nbr
2172 rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...)
2173 a += rows[i]
2174 end
2175 T[rs...;]
2176 end
2177
2178 ## N-dimensional concatenation ##
2179
2180 """
2181 hvncat(dim::Int, row_first, values...)
2182 hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2183 hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2184
2185 Horizontal, vertical, and n-dimensional concatenation of many `values` in one call.
2186
2187 This function is called for block matrix syntax. The first argument either specifies the
2188 shape of the concatenation, similar to `hvcat`, as a tuple of tuples, or the dimensions that
2189 specify the key number of elements along each axis, and is used to determine the output
2190 dimensions. The `dims` form is more performant, and is used by default when the concatenation
2191 operation has the same number of elements along each axis (e.g., [a b; c d;;; e f ; g h]).
2192 The `shape` form is used when the number of elements along each axis is unbalanced
2193 (e.g., [a b ; c]). Unbalanced syntax needs additional validation overhead. The `dim` form
2194 is an optimization for concatenation along just one dimension. `row_first` indicates how
2195 `values` are ordered. The meaning of the first and second elements of `shape` are also
2196 swapped based on `row_first`.
2197
2198 # Examples
2199 ```jldoctest
2200 julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2201 (1, 2, 3, 4, 5, 6)
2202
2203 julia> [a b c;;; d e f]
2204 1×3×2 Array{Int64, 3}:
2205 [:, :, 1] =
2206 1 2 3
2207
2208 [:, :, 2] =
2209 4 5 6
2210
2211 julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2212 2×1×3 Array{Int64, 3}:
2213 [:, :, 1] =
2214 1
2215 2
2216
2217 [:, :, 2] =
2218 3
2219 4
2220
2221 [:, :, 3] =
2222 5
2223 6
2224
2225 julia> [a b;;; c d;;; e f]
2226 1×2×3 Array{Int64, 3}:
2227 [:, :, 1] =
2228 1 2
2229
2230 [:, :, 2] =
2231 3 4
2232
2233 [:, :, 3] =
2234 5 6
2235
2236 julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2237 1×3×2 Array{Int64, 3}:
2238 [:, :, 1] =
2239 1 2 3
2240
2241 [:, :, 2] =
2242 4 5 6
2243 ```
2244
2245 # Examples for construction of the arguments
2246 ```
2247 [a b c ; d e f ;;;
2248 g h i ; j k l ;;;
2249 m n o ; p q r ;;;
2250 s t u ; v w x]
2251 ⇒ dims = (2, 3, 4)
2252
2253 [a b ; c ;;; d ;;;;]
2254 ___ _ _
2255 2 1 1 = elements in each row (2, 1, 1)
2256 _______ _
2257 3 1 = elements in each column (3, 1)
2258 _____________
2259 4 = elements in each 3d slice (4,)
2260 _____________
2261 4 = elements in each 4d slice (4,)
2262 ⇒ shape = ((2, 1, 1), (3, 1), (4,), (4,)) with `row_first` = true
2263 ```
2264 """
2265 hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...)
2266 hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...)
2267
2268 _hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
2269 _hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
2270 _hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
2271 _hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
2272 _hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
2273 _hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
2274
2275
2276 typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
2277 typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
2278
2279 # 1-dimensional hvncat methods
2280
2281 _typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
2282 _typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
2283 _typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
2284 _typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
2285 _typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
2286 _typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
2287 _typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
2288
2289 _typed_hvncat_0d_only_one() =
2290 throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2291
2292 # `@constprop :aggressive` here to form constant `Val(dim)` type to get type stability
2293 @constprop :aggressive _typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters
2294
2295 function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
2296 N < 0 &&
2297 throw(ArgumentError("concatenation dimension must be nonnegative"))
2298 return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
2299 end
2300
2301 function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
2302 N < 0 &&
2303 throw(ArgumentError("concatenation dimension must be nonnegative"))
2304 A = cat_similar(xs[1], T, (ntuple(x -> 1, Val(N - 1))..., length(xs)))
2305 hvncat_fill!(A, false, xs)
2306 return A
2307 end
2308
2309 function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
2310 # optimization for arrays that can be concatenated by copying them linearly into the destination
2311 # conditions: the elements must all have 1-length dimensions above N
2312 length(as) > 0 ||
2313 throw(ArgumentError("must have at least one element"))
2314 N < 0 &&
2315 throw(ArgumentError("concatenation dimension must be nonnegative"))
2316 for a ∈ as
2317 ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) ||
2318 return _typed_hvncat(T, (ntuple(x -> 1, Val(N - 1))..., length(as), 1), false, as...)
2319 # the extra 1 is to avoid an infinite cycle
2320 end
2321
2322 nd = N
2323
2324 Ndim = 0
2325 for i ∈ eachindex(as)
2326 Ndim += cat_size(as[i], N)
2327 nd = max(nd, cat_ndims(as[i]))
2328 for d ∈ 1:N - 1
2329 cat_size(as[1], d) == cat_size(as[i], d) || throw(DimensionMismatch("mismatched size along axis $d in element $i"))
2330 end
2331 end
2332
2333 A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
2334 k = 1
2335 for a ∈ as
2336 for i ∈ eachindex(a)
2337 A[k] = a[i]
2338 k += 1
2339 end
2340 end
2341 return A
2342 end
2343
2344 function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
2345 length(as) > 0 ||
2346 throw(ArgumentError("must have at least one element"))
2347 N < 0 &&
2348 throw(ArgumentError("concatenation dimension must be nonnegative"))
2349 nd = N
2350 Ndim = 0
2351 for i ∈ eachindex(as)
2352 Ndim += cat_size(as[i], N)
2353 nd = max(nd, cat_ndims(as[i]))
2354 for d ∈ 1:N-1
2355 cat_size(as[i], d) == 1 ||
2356 throw(DimensionMismatch("all dimensions of element $i other than $N must be of length 1"))
2357 end
2358 end
2359
2360 A = Array{T, nd}(undef, ntuple(x -> 1, Val(N - 1))..., Ndim, ntuple(x -> 1, nd - N)...)
2361
2362 k = 1
2363 for a ∈ as
2364 if a isa AbstractArray
2365 lena = length(a)
2366 copyto!(A, k, a, 1, lena)
2367 k += lena
2368 else
2369 A[k] = a
2370 k += 1
2371 end
2372 end
2373 return A
2374 end
2375
2376 # 0-dimensional cases for balanced and unbalanced hvncat method
2377
2378 _typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2379 _typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
2380
2381
2382 # balanced dimensions hvncat methods
2383
2384 _typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
2385 _typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as::Number...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
2386
2387 function _typed_hvncat_1d(::Type{T}, ds::Int, ::Val{row_first}, as...) where {T, row_first}
2388 lengthas = length(as)
2389 ds > 0 ||
2390 throw(ArgumentError("`dimsshape` argument must consist of positive integers"))
2391 lengthas == ds ||
2392 throw(ArgumentError("number of elements does not match `dimshape` argument; expected $ds, got $lengthas"))
2393 if row_first
2394 return _typed_hvncat(T, Val(2), as...)
2395 else
2396 return _typed_hvncat(T, Val(1), as...)
2397 end
2398 end
2399
2400 function _typed_hvncat(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, xs::Number...) where {T, N}
2401 all(>(0), dims) ||
2402 throw(ArgumentError("`dims` argument must contain positive integers"))
2403 A = Array{T, N}(undef, dims...)
2404 lengtha = length(A) # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations
2405 lengthx = length(xs) # Cuts from 3 allocations to 1.
2406 if lengtha != lengthx
2407 throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)"))
2408 end
2409 hvncat_fill!(A, row_first, xs)
2410 return A
2411 end
2412
2413 function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
2414 nr, nc = size(A, 1), size(A, 2)
2415 na = prod(size(A)[3:end])
2416 len = length(xs)
2417 nrc = nr * nc
2418 if nrc * na != len
2419 throw(ArgumentError("argument count $(len) does not match specified shape $(size(A))"))
2420 end
2421 # putting these in separate functions leads to unnecessary allocations
2422 if row_first
2423 k = 1
2424 for d ∈ 1:na
2425 dd = nrc * (d - 1)
2426 for i ∈ 1:nr
2427 Ai = dd + i
2428 for j ∈ 1:nc
2429 @inbounds A[Ai] = xs[k]
2430 k += 1
2431 Ai += nr
2432 end
2433 end
2434 end
2435 else
2436 for k ∈ eachindex(xs)
2437 @inbounds A[k] = xs[k]
2438 end
2439 end
2440 end
2441
2442 function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
2443 # function barrier after calculating the max is necessary for high performance
2444 nd = max(maximum(cat_ndims(a) for a ∈ as), N)
2445 return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
2446 end
2447
2448 function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
2449 length(as) > 0 ||
2450 throw(ArgumentError("must have at least one element"))
2451 all(>(0), dims) ||
2452 throw(ArgumentError("`dims` argument must contain positive integers"))
2453
2454 d1 = row_first ? 2 : 1
2455 d2 = row_first ? 1 : 2
2456
2457 outdims = zeros(Int, N)
2458
2459 # validate shapes for lowest level of concatenation
2460 d = findfirst(>(1), dims)
2461 if d !== nothing # all dims are 1
2462 if row_first && d < 3
2463 d = d == 1 ? 2 : 1
2464 end
2465 nblocks = length(as) ÷ dims[d]
2466 for b ∈ 1:nblocks
2467 offset = ((b - 1) * dims[d])
2468 startelementi = offset + 1
2469 for i ∈ offset .+ (2:dims[d])
2470 for dd ∈ 1:N
2471 dd == d && continue
2472 if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
2473 throw(DimensionMismatch("incompatible shape in element $i"))
2474 end
2475 end
2476 end
2477 end
2478 end
2479
2480 # discover number of rows or columns
2481 for i ∈ 1:dims[d1]
2482 outdims[d1] += cat_size(as[i], d1)
2483 end
2484
2485 currentdims = zeros(Int, N)
2486 blockcount = 0
2487 elementcount = 0
2488 for i ∈ eachindex(as)
2489 elementcount += cat_length(as[i])
2490 currentdims[d1] += cat_size(as[i], d1)
2491 if currentdims[d1] == outdims[d1]
2492 currentdims[d1] = 0
2493 for d ∈ (d2, 3:N...)
2494 currentdims[d] += cat_size(as[i], d)
2495 if outdims[d] == 0 # unfixed dimension
2496 blockcount += 1
2497 if blockcount == dims[d]
2498 outdims[d] = currentdims[d]
2499 currentdims[d] = 0
2500 blockcount = 0
2501 else
2502 break
2503 end
2504 else # fixed dimension
2505 if currentdims[d] == outdims[d] # end of dimension
2506 currentdims[d] = 0
2507 elseif currentdims[d] < outdims[d] # dimension in progress
2508 break
2509 else # exceeded dimension
2510 throw(DimensionMismatch("argument $i has too many elements along axis $d"))
2511 end
2512 end
2513 end
2514 elseif currentdims[d1] > outdims[d1] # exceeded dimension
2515 throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
2516 end
2517 end
2518
2519 outlen = prod(outdims)
2520 elementcount == outlen ||
2521 throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2522
2523 # copy into final array
2524 A = cat_similar(as[1], T, outdims)
2525 # @assert all(==(0), currentdims)
2526 outdims .= 0
2527 hvncat_fill!(A, currentdims, outdims, d1, d2, as)
2528 return A
2529 end
2530
2531
2532 # unbalanced dimensions hvncat methods
2533
2534 function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
2535 length(shape[1]) > 0 ||
2536 throw(ArgumentError("each level of `shape` argument must have at least one value"))
2537 return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
2538 end
2539
2540 function _typed_hvncat(T::Type, shape::NTuple{N, Tuple}, row_first::Bool, as...) where {N}
2541 # function barrier after calculating the max is necessary for high performance
2542 nd = max(maximum(cat_ndims(a) for a ∈ as), N)
2543 return _typed_hvncat_shape(T, (shape..., ntuple(x -> shape[end], nd - N)...), row_first, as)
2544 end
2545
2546 function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
2547 length(as) > 0 ||
2548 throw(ArgumentError("must have at least one element"))
2549 all(>(0), tuple((shape...)...)) ||
2550 throw(ArgumentError("`shape` argument must consist of positive integers"))
2551
2552 d1 = row_first ? 2 : 1
2553 d2 = row_first ? 1 : 2
2554
2555 shapev = collect(shape) # saves allocations later
2556 all(!isempty, shapev) ||
2557 throw(ArgumentError("each level of `shape` argument must have at least one value"))
2558 length(shapev[end]) == 1 ||
2559 throw(ArgumentError("last level of shape must contain only one integer"))
2560 shapelength = shapev[end][1]
2561 lengthas = length(as)
2562 shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)"))
2563 # discover dimensions
2564 nd = max(N, cat_ndims(as[1]))
2565 outdims = fill(-1, nd)
2566 currentdims = zeros(Int, nd)
2567 blockcounts = zeros(Int, nd)
2568 shapepos = ones(Int, nd)
2569
2570 elementcount = 0
2571 for i ∈ eachindex(as)
2572 elementcount += cat_length(as[i])
2573 wasstartblock = false
2574 for d ∈ 1:N
2575 ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
2576 dsize = cat_size(as[i], ad)
2577 blockcounts[d] += 1
2578
2579 if d == 1 || i == 1 || wasstartblock
2580 currentdims[d] += dsize
2581 elseif dsize != cat_size(as[i - 1], ad)
2582 throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
2583 expected $(cat_size(as[i - 1], ad)), got $dsize"))
2584 end
2585
2586 wasstartblock = blockcounts[d] == 1 # remember for next dimension
2587
2588 isendblock = blockcounts[d] == shapev[d][shapepos[d]]
2589 if isendblock
2590 if outdims[d] == -1
2591 outdims[d] = currentdims[d]
2592 elseif outdims[d] != currentdims[d]
2593 throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
2594 expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2595 end
2596 currentdims[d] = 0
2597 blockcounts[d] = 0
2598 shapepos[d] += 1
2599 d > 1 && (blockcounts[d - 1] == 0 ||
2600 throw(DimensionMismatch("shape in level $d is inconsistent; level counts must nest \
2601 evenly into each other")))
2602 end
2603 end
2604 end
2605
2606 outlen = prod(outdims)
2607 elementcount == outlen ||
2608 throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2609
2610 if row_first
2611 outdims[1], outdims[2] = outdims[2], outdims[1]
2612 end
2613
2614 # @assert all(==(0), currentdims)
2615 # @assert all(==(0), blockcounts)
2616
2617 # copy into final array
2618 A = cat_similar(as[1], T, outdims)
2619 hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
2620 return A
2621 end
2622
2623 function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int},
2624 d1::Int, d2::Int, as::Tuple) where {T, N}
2625 N > 1 || throw(ArgumentError("dimensions of the destination array must be at least 2"))
2626 length(scratch1) == length(scratch2) == N ||
2627 throw(ArgumentError("scratch vectors must have as many elements as the destination array has dimensions"))
2628 0 < d1 < 3 &&
2629 0 < d2 < 3 &&
2630 d1 != d2 ||
2631 throw(ArgumentError("d1 and d2 must be either 1 or 2, exclusive."))
2632 outdims = size(A)
2633 offsets = scratch1
2634 inneroffsets = scratch2
2635 for a ∈ as
2636 if isa(a, AbstractArray)
2637 for ai ∈ a
2638 @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
2639 A[Ai] = ai
2640
2641 @inbounds for j ∈ 1:N
2642 inneroffsets[j] += 1
2643 inneroffsets[j] < cat_size(a, j) && break
2644 inneroffsets[j] = 0
2645 end
2646 end
2647 else
2648 @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
2649 A[Ai] = a
2650 end
2651
2652 @inbounds for j ∈ (d1, d2, 3:N...)
2653 offsets[j] += cat_size(a, j)
2654 offsets[j] < outdims[j] && break
2655 offsets[j] = 0
2656 end
2657 end
2658 end
2659
2660 @propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
2661 outdims::Tuple{Vararg{Int}}, nd::Int)
2662 Ai = inneroffsets[1] + offsets[1] + 1
2663 for j ∈ 2:nd
2664 increment = inneroffsets[j] + offsets[j]
2665 for k ∈ 1:j-1
2666 increment *= outdims[k]
2667 end
2668 Ai += increment
2669 end
2670 Ai
2671 end
2672
2673 """
2674 stack(iter; [dims])
2675
2676 Combine a collection of arrays (or other iterable objects) of equal size
2677 into one larger array, by arranging them along one or more new dimensions.
2678
2679 By default the axes of the elements are placed first,
2680 giving `size(result) = (size(first(iter))..., size(iter)...)`.
2681 This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2682
2683 With keyword `dims::Integer`, instead the `i`th element of `iter` becomes the slice
2684 [`selectdim`](@ref)`(result, dims, i)`, so that `size(result, dims) == length(iter)`.
2685 In this case `stack` reverses the action of [`eachslice`](@ref) with the same `dims`.
2686
2687 The various [`cat`](@ref) functions also combine arrays. However, these all
2688 extend the arrays' existing (possibly trivial) dimensions, rather than placing
2689 the arrays along new dimensions.
2690 They also accept arrays as separate arguments, rather than a single collection.
2691
2692 !!! compat "Julia 1.9"
2693 This function requires at least Julia 1.9.
2694
2695 # Examples
2696 ```jldoctest
2697 julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2698
2699 julia> mat = stack(vecs)
2700 2×3 Matrix{Float32}:
2701 1.0 30.0 500.0
2702 2.0 40.0 600.0
2703
2704 julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2705 true
2706
2707 julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2708 true
2709
2710 julia> stack(zip(1:4, 10:99)) # accepts any iterators of iterators
2711 2×4 Matrix{Int64}:
2712 1 2 3 4
2713 10 11 12 13
2714
2715 julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2716 true
2717
2718 julia> stack(vecs; dims=1) # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2719 3×2 Matrix{Float32}:
2720 1.0 2.0
2721 30.0 40.0
2722 500.0 600.0
2723
2724 julia> x = rand(3,4);
2725
2726 julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1) # inverse of eachslice
2727 true
2728 ```
2729
2730 Higher-dimensional examples:
2731
2732 ```jldoctest
2733 julia> A = rand(5, 7, 11);
2734
2735 julia> E = eachslice(A, dims=2); # a vector of matrices
2736
2737 julia> (element = size(first(E)), container = size(E))
2738 (element = (5, 11), container = (7,))
2739
2740 julia> stack(E) |> size
2741 (5, 11, 7)
2742
2743 julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2744 true
2745
2746 julia> A == stack(E; dims=2)
2747 true
2748
2749 julia> M = (fill(10i+j, 2, 3) for i in 1:5, j in 1:7);
2750
2751 julia> (element = size(first(M)), container = size(M))
2752 (element = (2, 3), container = (5, 7))
2753
2754 julia> stack(M) |> size # keeps all dimensions
2755 (2, 3, 5, 7)
2756
2757 julia> stack(M; dims=1) |> size # vec(container) along dims=1
2758 (35, 2, 3)
2759
2760 julia> hvcat(5, M...) |> size # hvcat puts matrices next to each other
2761 (14, 15)
2762 ```
2763 """
2764 stack(iter; dims=:) = _stack(dims, iter)
2765
2766 """
2767 stack(f, args...; [dims])
2768
2769 Apply a function to each element of a collection, and `stack` the result.
2770 Or to several collections, [`zip`](@ref)ped together.
2771
2772 The function should return arrays (or tuples, or other iterators) all of the same size.
2773 These become slices of the result, each separated along `dims` (if given) or by default
2774 along the last dimensions.
2775
2776 See also [`mapslices`](@ref), [`eachcol`](@ref).
2777
2778 # Examples
2779 ```jldoctest
2780 julia> stack(c -> (c, c-32), "julia")
2781 2×5 Matrix{Char}:
2782 'j' 'u' 'l' 'i' 'a'
2783 'J' 'U' 'L' 'I' 'A'
2784
2785 julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2786 vcat(row, row .* n, row ./ n)
2787 end
2788 2×9 Matrix{Float64}:
2789 1.0 2.0 3.0 10.0 20.0 30.0 0.1 0.2 0.3
2790 4.0 5.0 6.0 400.0 500.0 600.0 0.04 0.05 0.06
2791 ```
2792 """
2793 stack(f, iter; dims=:) = _stack(dims, f(x) for x in iter)
2794 stack(f, xs, yzs...; dims=:) = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
2795
2796 _stack(dims::Union{Integer, Colon}, iter) = _stack(dims, IteratorSize(iter), iter)
2797
2798 _stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
2799
2800 function _stack(dims, ::Union{HasShape, HasLength}, iter)
2801 S = @default_eltype iter
2802 T = S != Union{} ? eltype(S) : Any # Union{} occurs for e.g. stack(1,2), postpone the error
2803 if isconcretetype(T)
2804 _typed_stack(dims, T, S, iter)
2805 else # Need to look inside, but shouldn't run an expensive iterator twice:
2806 array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
2807 isempty(array) && return _empty_stack(dims, T, S, iter)
2808 T2 = mapreduce(eltype, promote_type, array)
2809 _typed_stack(dims, T2, eltype(array), array)
2810 end
2811 end
2812
2813 function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
2814 xit = iterate(A)
2815 nothing === xit && return _empty_stack(:, T, S, A)
2816 x1, _ = xit
2817 ax1 = _iterator_axes(x1)
2818 B = similar(_ensure_array(x1), T, ax1..., Aax...)
2819 off = firstindex(B)
2820 len = length(x1)
2821 while xit !== nothing
2822 x, state = xit
2823 _stack_size_check(x, ax1)
2824 copyto!(B, off, x)
2825 off += len
2826 xit = iterate(A, state)
2827 end
2828 B
2829 end
2830
2831 _iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
2832 _iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
2833 _iterator_axes(x, ::IteratorSize) = axes(x)
2834
2835 # For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2836 _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
2837 _typed_stack(dims, T, S, IteratorSize(S), A)
2838 _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
2839 _typed_stack(dims, T, S, HasShape{1}(), A)
2840 function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
2841 if dims == N+1
2842 _typed_stack(:, T, S, A, (_vec_axis(A),))
2843 else
2844 _dim_stack(dims, T, S, A)
2845 end
2846 end
2847 _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
2848 _dim_stack(dims, T, S, A)
2849
2850 _vec_axis(A, ax=_iterator_axes(A)) = length(ax) == 1 ? only(ax) : OneTo(prod(length, ax; init=1))
2851
2852 @constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
2853 xit = Iterators.peel(A)
2854 nothing === xit && return _empty_stack(dims, T, S, A)
2855 x1, xrest = xit
2856 ax1 = _iterator_axes(x1)
2857 N1 = length(ax1)+1
2858 dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
2859
2860 newaxis = _vec_axis(A)
2861 outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
2862 B = similar(_ensure_array(x1), T, outax...)
2863
2864 if dims == 1
2865 _dim_stack!(Val(1), B, x1, xrest)
2866 elseif dims == 2
2867 _dim_stack!(Val(2), B, x1, xrest)
2868 else
2869 _dim_stack!(Val(dims), B, x1, xrest)
2870 end
2871 B
2872 end
2873
2874 function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
2875 before = ntuple(d -> Colon(), dims - 1)
2876 after = ntuple(d -> Colon(), ndims(B) - dims)
2877
2878 i = firstindex(B, dims)
2879 copyto!(view(B, before..., i, after...), x1)
2880
2881 for x in xrest
2882 _stack_size_check(x, _iterator_axes(x1))
2883 i += 1
2884 @inbounds copyto!(view(B, before..., i, after...), x)
2885 end
2886 end
2887
2888 @inline function _stack_size_check(x, ax1::Tuple)
2889 if _iterator_axes(x) != ax1
2890 uax1 = map(UnitRange, ax1)
2891 uaxN = map(UnitRange, axes(x))
2892 throw(DimensionMismatch(
2893 LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
2894 end
2895 end
2896
2897 _ensure_array(x::AbstractArray) = x
2898 _ensure_array(x) = 1:0 # passed to similar, makes stack's output an Array
2899
2900 _empty_stack(_...) = throw(ArgumentError("`stack` on an empty collection is not allowed"))
2901
2902
2903 ## Reductions and accumulates ##
2904
2905 function isequal(A::AbstractArray, B::AbstractArray)
2906 if A === B return true end
2907 if axes(A) != axes(B)
2908 return false
2909 end
2910 for (a, b) in zip(A, B)
2911 if !isequal(a, b)
2912 return false
2913 end
2914 end
2915 return true
2916 end
2917
2918 function cmp(A::AbstractVector, B::AbstractVector)
2919 for (a, b) in zip(A, B)
2920 if !isequal(a, b)
2921 return isless(a, b) ? -1 : 1
2922 end
2923 end
2924 return cmp(length(A), length(B))
2925 end
2926
2927 """
2928 isless(A::AbstractVector, B::AbstractVector)
2929
2930 Return `true` when `A` is less than `B` in lexicographic order.
2931 """
2932 isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
2933
2934 function (==)(A::AbstractArray, B::AbstractArray)
2935 if axes(A) != axes(B)
2936 return false
2937 end
2938 anymissing = false
2939 for (a, b) in zip(A, B)
2940 eq = (a == b)
2941 if ismissing(eq)
2942 anymissing = true
2943 elseif !eq
2944 return false
2945 end
2946 end
2947 return anymissing ? missing : true
2948 end
2949
2950 # _sub2ind and _ind2sub
2951 # fallbacks
2952 function _sub2ind(A::AbstractArray, I...)
2953 @inline
2954 _sub2ind(axes(A), I...)
2955 end
2956
2957 function _ind2sub(A::AbstractArray, ind)
2958 @inline
2959 _ind2sub(axes(A), ind)
2960 end
2961
2962 # 0-dimensional arrays and indexing with []
2963 _sub2ind(::Tuple{}) = 1
2964 _sub2ind(::DimsInteger) = 1
2965 _sub2ind(::Indices) = 1
2966 _sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
2967
2968 # Generic cases
2969 _sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
2970 _sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
2971 # In 1d, there's a question of whether we're doing cartesian indexing
2972 # or linear indexing. Support only the former.
2973 _sub2ind(inds::Indices{1}, I::Integer...) =
2974 throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2975 _sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
2976 _sub2ind(inds::Tuple{OneTo}, i::Integer) = i
2977
2978 _sub2ind_recurse(::Any, L, ind) = ind
2979 function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
2980 @inline
2981 _sub2ind_recurse((), L, ind+(i-1)*L, I...)
2982 end
2983 function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
2984 @inline
2985 r1 = inds[1]
2986 _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
2987 end
2988
2989 nextL(L, l::Integer) = L*l
2990 nextL(L, r::AbstractUnitRange) = L*length(r)
2991 nextL(L, r::Slice) = L*length(r.indices)
2992 offsetin(i, l::Integer) = i-1
2993 offsetin(i, r::AbstractUnitRange) = i-first(r)
2994
2995 _ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
2996 _ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
2997 _ind2sub(inds::Indices, ind::Integer) = (@inline; _ind2sub_recurse(inds, ind-1))
2998 _ind2sub(inds::Indices{1}, ind::Integer) =
2999 throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3000 _ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
3001
3002 _ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
3003 function _ind2sub_recurse(indslast::NTuple{1}, ind)
3004 @inline
3005 (_lookup(ind, indslast[1]),)
3006 end
3007 function _ind2sub_recurse(inds, ind)
3008 @inline
3009 r1 = inds[1]
3010 indnext, f, l = _div(ind, r1)
3011 (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
3012 end
3013
3014 _lookup(ind, d::Integer) = ind+1
3015 _lookup(ind, r::AbstractUnitRange) = ind+first(r)
3016 _div(ind, d::Integer) = div(ind, d), 1, d
3017 _div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
3018
3019 # Vectorized forms
3020 function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
3021 throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3022 end
3023 _sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
3024 _sub2ind_vecs(inds, I1, I...)
3025 _sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
3026 _sub2ind_vecs(inds, I1, I...)
3027 function _sub2ind_vecs(inds, I::AbstractVector...)
3028 I1 = I[1]
3029 Iinds = axes1(I1)
3030 for j = 2:length(I)
3031 axes1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(axes1(I[j])))"))
3032 end
3033 Iout = similar(I1)
3034 _sub2ind!(Iout, inds, Iinds, I)
3035 Iout
3036 end
3037
3038 function _sub2ind!(Iout, inds, Iinds, I)
3039 @noinline
3040 for i in Iinds
3041 # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3042 Iout[i] = sub2ind_vec(inds, i, I)
3043 end
3044 Iout
3045 end
3046
3047 sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
3048 _sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
3049 _sub2ind_vec(i) = ()
3050
3051 function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
3052 M = length(ind)
3053 t = ntuple(n->similar(ind),Val(N))
3054 for (i,idx) in pairs(IndexLinear(), ind)
3055 sub = _ind2sub(inds, idx)
3056 for j = 1:N
3057 t[j][i] = sub[j]
3058 end
3059 end
3060 t
3061 end
3062
3063 ## iteration utilities ##
3064
3065 """
3066 foreach(f, c...) -> Nothing
3067
3068 Call function `f` on each element of iterable `c`.
3069 For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3070 any iterator is finished.
3071
3072 `foreach` should be used instead of [`map`](@ref) when the results of `f` are not
3073 needed, for example in `foreach(println, array)`.
3074
3075 # Examples
3076 ```jldoctest
3077 julia> tri = 1:3:7; res = Int[];
3078
3079 julia> foreach(x -> push!(res, x^2), tri)
3080
3081 julia> res
3082 3-element Vector{$(Int)}:
3083 1
3084 16
3085 49
3086
3087 julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3088 1 with a
3089 4 with b
3090 7 with c
3091 ```
3092 """
3093 foreach(f) = (f(); nothing)
3094 foreach(f, itr) = (for x in itr; f(x); end; nothing)
3095 foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
3096
3097 ## map over arrays ##
3098
3099 ## transform any set of dimensions
3100 ## dims specifies which dimensions will be transformed. for example
3101 ## dims==1:2 will call f on all slices A[:,:,...]
3102 """
3103 mapslices(f, A; dims)
3104
3105 Transform the given dimensions of array `A` by applying a function `f` on each slice
3106 of the form `A[..., :, ..., :, ...]`, with a colon at each `d` in `dims`. The results are
3107 concatenated along the remaining dimensions.
3108
3109 For example, if `dims = [1,2]` and `A` is 4-dimensional, then `f` is called on `x = A[:,:,i,j]`
3110 for all `i` and `j`, and `f(x)` becomes `R[:,:,i,j]` in the result `R`.
3111
3112 See also [`eachcol`](@ref) or [`eachslice`](@ref), used with [`map`](@ref) or [`stack`](@ref).
3113
3114 # Examples
3115 ```jldoctest
3116 julia> A = reshape(1:30,(2,5,3))
3117 2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3118 [:, :, 1] =
3119 1 3 5 7 9
3120 2 4 6 8 10
3121
3122 [:, :, 2] =
3123 11 13 15 17 19
3124 12 14 16 18 20
3125
3126 [:, :, 3] =
3127 21 23 25 27 29
3128 22 24 26 28 30
3129
3130 julia> f(x::Matrix) = fill(x[1,1], 1,4); # returns a 1×4 matrix
3131
3132 julia> B = mapslices(f, A, dims=(1,2))
3133 1×4×3 Array{$Int, 3}:
3134 [:, :, 1] =
3135 1 1 1 1
3136
3137 [:, :, 2] =
3138 11 11 11 11
3139
3140 [:, :, 3] =
3141 21 21 21 21
3142
3143 julia> f2(x::AbstractMatrix) = fill(x[1,1], 1,4);
3144
3145 julia> B == stack(f2, eachslice(A, dims=3))
3146 true
3147
3148 julia> g(x) = x[begin] // x[end-1]; # returns a number
3149
3150 julia> mapslices(g, A, dims=[1,3])
3151 1×5×1 Array{Rational{$Int}, 3}:
3152 [:, :, 1] =
3153 1//21 3//23 1//5 7//27 9//29
3154
3155 julia> map(g, eachslice(A, dims=2))
3156 5-element Vector{Rational{$Int}}:
3157 1//21
3158 3//23
3159 1//5
3160 7//27
3161 9//29
3162
3163 julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3164 true
3165 ```
3166
3167 Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3168 one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3169 `mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3170 values in the slice without affecting `A`.
3171 """
3172 function mapslices(f, A::AbstractArray; dims)
3173 isempty(dims) && return map(f, A)
3174
3175 for d in dims
3176 d isa Integer || throw(ArgumentError("mapslices: dimension must be an integer, got $d"))
3177 d >= 1 || throw(ArgumentError("mapslices: dimension must be ≥ 1, got $d"))
3178 # Indexing a matrix M[:,1,:] produces a 1-column matrix, but dims=(1,3) here
3179 # would otherwise ignore 3, and slice M[:,i]. Previously this gave error:
3180 # BoundsError: attempt to access 2-element Vector{Any} at index [3]
3181 d > ndims(A) && throw(ArgumentError("mapslices does not accept dimensions > ndims(A) = $(ndims(A)), got $d"))
3182 end
3183 dim_mask = ntuple(d -> d in dims, ndims(A))
3184
3185 # Apply the function to the first slice in order to determine the next steps
3186 idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3187 Aslice = A[idx1...]
3188 r1 = f(Aslice)
3189
3190 res1 = if r1 isa AbstractArray && ndims(r1) > 0
3191 n = sum(dim_mask)
3192 if ndims(r1) > n && any(ntuple(d -> size(r1,d+n)>1, ndims(r1)-n))
3193 s = size(r1)[1:n]
3194 throw(DimensionMismatch("mapslices cannot assign slice f(x) of size $(size(r1)) into output of size $s"))
3195 end
3196 r1
3197 else
3198 # If the result of f on a single slice is a scalar then we add singleton
3199 # dimensions. When adding the dimensions, we have to respect the
3200 # index type of the input array (e.g. in the case of OffsetArrays)
3201 _res1 = similar(Aslice, typeof(r1), reduced_indices(Aslice, 1:ndims(Aslice)))
3202 _res1[begin] = r1
3203 _res1
3204 end
3205
3206 # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3207 din = Ref(0)
3208 Rsize = ntuple(ndims(A)) do d
3209 if d in dims
3210 axes(res1, din[] += 1)
3211 else
3212 axes(A,d)
3213 end
3214 end
3215 R = similar(res1, Rsize)
3216
3217 # Determine iteration space. It will be convenient in the loop to mask N-dimensional
3218 # CartesianIndices, with some trivial dimensions:
3219 itershape = ntuple(d -> d in dims ? Base.OneTo(1) : axes(A,d), ndims(A))
3220 indices = Iterators.drop(CartesianIndices(itershape), 1)
3221
3222 # That skips the first element, which we already have:
3223 ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
3224 concatenate_setindex!(R, res1, ridx...)
3225
3226 # In some cases, we can re-use the first slice for a dramatic performance
3227 # increase. The slice itself must be mutable and the result cannot contain
3228 # any mutable containers. The following errs on the side of being overly
3229 # strict (#18570 & #21123).
3230 safe_for_reuse = isa(Aslice, StridedArray) &&
3231 (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number))
3232
3233 _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
3234 return R
3235 end
3236
3237 @noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
3238 must_extend = any(dim_mask .& size(R) .> 1)
3239 if safe_for_reuse
3240 # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3241 # so we can reuse Aslice
3242 for I in indices
3243 idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
3244 _unsafe_getindex!(Aslice, A, idx...)
3245 r = f(Aslice)
3246 if r isa AbstractArray || must_extend
3247 ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
3248 R[ridx...] = r
3249 else
3250 ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
3251 R[ridx...] = r
3252 end
3253 end
3254 else
3255 # we can't guarantee safety (#18524), so allocate new storage for each slice
3256 for I in indices
3257 idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
3258 ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
3259 concatenate_setindex!(R, f(A[idx...]), ridx...)
3260 end
3261 end
3262 end
3263
3264 concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
3265 concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
3266
3267 ## 0 arguments
3268
3269 map(f) = f()
3270
3271 ## 1 argument
3272
3273 function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3274 for (i,j) in zip(eachindex(dest),eachindex(A))
3275 val = f(@inbounds A[j])
3276 @inbounds dest[i] = val
3277 end
3278 return dest
3279 end
3280
3281 # map on collections
3282 map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
3283
3284 mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
3285 mapany(f, itr) = Any[f(x) for x in itr]
3286
3287 """
3288 map(f, c...) -> collection
3289
3290 Transform collection `c` by applying `f` to each element. For multiple collection arguments,
3291 apply `f` elementwise, and stop when any of them is exhausted.
3292
3293 See also [`map!`](@ref), [`foreach`](@ref), [`mapreduce`](@ref), [`mapslices`](@ref), [`zip`](@ref), [`Iterators.map`](@ref).
3294
3295 # Examples
3296 ```jldoctest
3297 julia> map(x -> x * 2, [1, 2, 3])
3298 3-element Vector{Int64}:
3299 2
3300 4
3301 6
3302
3303 julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3304 3-element Vector{Int64}:
3305 11
3306 22
3307 33
3308 ```
3309 """
3310 map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
3311
3312 map(f, ::AbstractDict) = error("map is not defined on dictionaries")
3313 map(f, ::AbstractSet) = error("map is not defined on sets")
3314
3315 ## 2 argument
3316 function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
3317 for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
3318 @inbounds a, b = A[j], B[k]
3319 val = f(a, b)
3320 @inbounds dest[i] = val
3321 end
3322 return dest
3323 end
3324
3325 ## N argument
3326
3327 @inline ith_all(i, ::Tuple{}) = ()
3328 function ith_all(i, as)
3329 @_propagate_inbounds_meta
3330 return (as[1][i], ith_all(i, tail(as))...)
3331 end
3332
3333 function map_n!(f::F, dest::AbstractArray, As) where F
3334 idxs1 = LinearIndices(As[1])
3335 @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
3336 for i = idxs1
3337 @inbounds I = ith_all(i, As)
3338 val = f(I...)
3339 @inbounds dest[i] = val
3340 end
3341 return dest
3342 end
3343
3344 """
3345 map!(function, destination, collection...)
3346
3347 Like [`map`](@ref), but stores the result in `destination` rather than a new
3348 collection. `destination` must be at least as large as the smallest collection.
3349
3350 $(_DOCS_ALIASING_WARNING)
3351
3352 See also: [`map`](@ref), [`foreach`](@ref), [`zip`](@ref), [`copyto!`](@ref).
3353
3354 # Examples
3355 ```jldoctest
3356 julia> a = zeros(3);
3357
3358 julia> map!(x -> x * 2, a, [1, 2, 3]);
3359
3360 julia> a
3361 3-element Vector{Float64}:
3362 2.0
3363 4.0
3364 6.0
3365
3366 julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3367 5-element Vector{$(Int)}:
3368 101
3369 103
3370 105
3371 0
3372 0
3373 ```
3374 """
3375 function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
3376 isempty(As) && throw(ArgumentError(
3377 """map! requires at least one "source" argument"""))
3378 map_n!(f, dest, As)
3379 end
3380
3381 """
3382 map(f, A::AbstractArray...) -> N-array
3383
3384 When acting on multi-dimensional arrays of the same [`ndims`](@ref),
3385 they must all have the same [`axes`](@ref), and the answer will too.
3386
3387 See also [`broadcast`](@ref), which allows mismatched sizes.
3388
3389 # Examples
3390 ```
3391 julia> map(//, [1 2; 3 4], [4 3; 2 1])
3392 2×2 Matrix{Rational{$Int}}:
3393 1//4 2//3
3394 3//2 4//1
3395
3396 julia> map(+, [1 2; 3 4], zeros(2,1))
3397 ERROR: DimensionMismatch
3398
3399 julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1)) # iterates until 3rd is exhausted
3400 3-element Vector{Float64}:
3401 2.0
3402 13.0
3403 102.0
3404 ```
3405 """
3406 map(f, iters...) = collect(Generator(f, iters...))
3407
3408 # multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3409 # (note: must not cause a dispatch loop when 1-item case is not defined)
3410 push!(A, a, b) = push!(push!(A, a), b)
3411 push!(A, a, b, c...) = push!(push!(A, a, b), c...)
3412 pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
3413 pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
3414
3415 ## hashing AbstractArray ##
3416
3417 const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3418 function hash(A::AbstractArray, h::UInt)
3419 h += hash_abstractarray_seed
3420 # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3421 # Instead hash the tuple of firsts and lasts along each dimension
3422 h = hash(map(first, axes(A)), h)
3423 h = hash(map(last, axes(A)), h)
3424
3425 # For short arrays, it's not worth doing anything complicated
3426 if length(A) < 8192
3427 for x in A
3428 h = hash(x, h)
3429 end
3430 return h
3431 end
3432
3433 # Goal: Hash approximately log(N) entries with a higher density of hashed elements
3434 # weighted towards the end and special consideration for repeated values. Colliding
3435 # hashes will often subsequently be compared by equality -- and equality between arrays
3436 # works elementwise forwards and is short-circuiting. This means that a collision
3437 # between arrays that differ by elements at the beginning is cheaper than one where the
3438 # difference is towards the end. Furthermore, choosing `log(N)` arbitrary entries from a
3439 # sparse array will likely only choose the same element repeatedly (zero in this case).
3440
3441 # To achieve this, we work backwards, starting by hashing the last element of the
3442 # array. After hashing each element, we skip `fibskip` elements, where `fibskip`
3443 # is pulled from the Fibonacci sequence -- Fibonacci was chosen as a simple
3444 # ~O(log(N)) algorithm that ensures we don't hit a common divisor of a dimension
3445 # and only end up hashing one slice of the array (as might happen with powers of
3446 # two). Finally, we find the next distinct value from the one we just hashed.
3447
3448 # This is a little tricky since skipping an integer number of values inherently works
3449 # with linear indices, but `findprev` uses `keys`. Hoist out the conversion "maps":
3450 ks = keys(A)
3451 key_to_linear = LinearIndices(ks) # Index into this map to compute the linear index
3452 linear_to_key = vec(ks) # And vice-versa
3453
3454 # Start at the last index
3455 keyidx = last(ks)
3456 linidx = key_to_linear[keyidx]
3457 fibskip = prevfibskip = oneunit(linidx)
3458 first_linear = first(LinearIndices(linear_to_key))
3459 n = 0
3460 while true
3461 n += 1
3462 # Hash the element
3463 elt = A[keyidx]
3464 h = hash(keyidx=>elt, h)
3465
3466 # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3467 linidx = key_to_linear[keyidx]
3468 linidx < fibskip + first_linear && break
3469 linidx -= fibskip
3470 keyidx = linear_to_key[linidx]
3471
3472 # Only increase the Fibonacci skip once every N iterations. This was chosen
3473 # to be big enough that all elements of small arrays get hashed while
3474 # obscenely large arrays are still tractable. With a choice of N=4096, an
3475 # entirely-distinct 8000-element array will have ~75% of its elements hashed,
3476 # with every other element hashed in the first half of the array. At the same
3477 # time, hashing a `typemax(Int64)`-length Float64 range takes about a second.
3478 if rem(n, 4096) == 0
3479 fibskip, prevfibskip = fibskip + prevfibskip, fibskip
3480 end
3481
3482 # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3483 keyidx = findprev(!isequal(elt), A, keyidx)
3484 keyidx === nothing && break
3485 end
3486
3487 return h
3488 end
3489
3490 # The semantics of `collect` are weird. Better to write our own
3491 function rest(a::AbstractArray{T}, state...) where {T}
3492 v = Vector{T}(undef, 0)
3493 # assume only very few items are taken from the front
3494 sizehint!(v, length(a))
3495 return foldl(push!, Iterators.rest(a, state...), init=v)
3496 end
3497
3498
3499 ## keepat! ##
3500
3501 # NOTE: since these use `@inbounds`, they are actually only intended for Vector and BitVector
3502
3503 function _keepat!(a::AbstractVector, inds)
3504 local prev
3505 i = firstindex(a)
3506 for k in inds
3507 if @isdefined(prev)
3508 prev < k || throw(ArgumentError("indices must be unique and sorted"))
3509 end
3510 ak = a[k] # must happen even when i==k for bounds checking
3511 if i != k
3512 @inbounds a[i] = ak # k > i, so a[i] is inbounds
3513 end
3514 prev = k
3515 i = nextind(a, i)
3516 end
3517 deleteat!(a, i:lastindex(a))
3518 return a
3519 end
3520
3521 function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
3522 length(m) == length(a) || throw(BoundsError(a, m))
3523 j = firstindex(a)
3524 for i in eachindex(a, m)
3525 @inbounds begin
3526 if m[i]
3527 i == j || (a[j] = a[i])
3528 j = nextind(a, j)
3529 end
3530 end
3531 end
3532 deleteat!(a, j:lastindex(a))
3533 end
3534
3535 ## 1-d circshift ##
3536 function circshift!(a::AbstractVector, shift::Integer)
3537 n = length(a)
3538 n == 0 && return
3539 shift = mod(shift, n)
3540 shift == 0 && return
3541 l = lastindex(a)
3542 reverse!(a, firstindex(a), l-shift)
3543 reverse!(a, l-shift+1, lastindex(a))
3544 reverse!(a)
3545 return a
3546 end