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

JuliaLang / julia / #37728

26 Mar 2024 03:46AM UTC coverage: 80.612% (-0.8%) from 81.423%
#37728

push

local

web-flow
Update zlib to 1.3.1 (#53841)

Released January 22, 2024

69920 of 86737 relevant lines covered (80.61%)

14456248.65 hits per line

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

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

21✔
3
### Multidimensional iterators
13✔
4
module IteratorsMD
5
    import .Base: eltype, length, size, first, last, in, getindex, setindex!,
13✔
6
                  min, max, zero, oneunit, isless, eachindex,
13✔
7
                  convert, show, iterate, promote_rule, to_indices
13✔
8

13✔
9
    import .Base: +, -, *, (:)
10
    import .Base: simd_outer_range, simd_inner_length, simd_index, setindex
13✔
11
    using .Base: to_index, fill_to_length, tail, safe_tail
13✔
12
    using .Base: IndexLinear, IndexCartesian, AbstractCartesianIndex,
13✔
13
        ReshapedArray, ReshapedArrayLF, OneTo, Fix1
13✔
14
    using .Base.Iterators: Reverse, PartitionIterator
15
    using .Base: @propagate_inbounds
24✔
16

24✔
17
    export CartesianIndex, CartesianIndices
24✔
18

24✔
19
    """
20
        CartesianIndex(i, j, k...)   -> I
21
        CartesianIndex((i, j, k...)) -> I
66✔
22

23
    Create a multidimensional index `I`, which can be used for
24
    indexing a multidimensional array `A`.  In particular, `A[I]` is
25
    equivalent to `A[i,j,k...]`.  One can freely mix integer and
26
    `CartesianIndex` indices; for example, `A[Ipre, i, Ipost]` (where
27
    `Ipre` and `Ipost` are `CartesianIndex` indices and `i` is an
13✔
28
    `Int`) can be a useful expression when writing algorithms that
29
    work along a single dimension of an array of arbitrary
30
    dimensionality.
31

32
    A `CartesianIndex` is sometimes produced by [`eachindex`](@ref), and
33
    always when iterating with an explicit [`CartesianIndices`](@ref).
34

35
    An `I::CartesianIndex` is treated as a "scalar" (not a container)
36
    for `broadcast`.   In order to iterate over the components of a
37
    `CartesianIndex`, convert it to a tuple with `Tuple(I)`.
38

39
    # Examples
40
    ```jldoctest
41
    julia> A = reshape(Vector(1:16), (2, 2, 2, 2))
42
    2×2×2×2 Array{Int64, 4}:
43
    [:, :, 1, 1] =
44
     1  3
45
     2  4
46

47
    [:, :, 2, 1] =
48
     5  7
49
     6  8
50

51
    [:, :, 1, 2] =
52
      9  11
77,568✔
53
     10  12
2,056✔
54

55
    [:, :, 2, 2] =
77,959✔
56
     13  15
57
     14  16
77,959✔
58

77,568✔
59
    julia> A[CartesianIndex((1, 1, 1, 1))]
60
    1
77,568✔
61

2,056✔
62
    julia> A[CartesianIndex((1, 1, 1, 2))]
77,568✔
63
    9
77,568✔
64

65
    julia> A[CartesianIndex((1, 1, 2, 1))]
5,255✔
66
    5
3,711✔
67
    ```
5,255✔
68

3,711✔
69
    !!! compat "Julia 1.10"
70
        Using a `CartesianIndex` as a "scalar" for `broadcast` requires
71
        Julia 1.10; in previous releases, use `Ref(I)`.
77,568✔
72
    """
79,503✔
73
    struct CartesianIndex{N} <: AbstractCartesianIndex{N}
15,966✔
74
        I::NTuple{N,Int}
75
        CartesianIndex{N}(index::NTuple{N,Integer}) where {N} = new(index)
321,133,758✔
76
    end
77

93,333✔
78
    CartesianIndex(index::NTuple{N,Integer}) where {N} = CartesianIndex{N}(index)
321,214,229✔
79
    CartesianIndex(index::Integer...) = CartesianIndex(index)
81,348,900✔
80
    CartesianIndex{N}(index::Vararg{Integer,N}) where {N} = CartesianIndex{N}(index)
77,887✔
81
    # Allow passing tuples smaller than N
82
    CartesianIndex{N}(index::Tuple) where {N} = CartesianIndex{N}(fill_to_length(index, 1, Val(N)))
5✔
83
    CartesianIndex{N}(index::Integer...) where {N} = CartesianIndex{N}(index)
2✔
84
    CartesianIndex{N}() where {N} = CartesianIndex{N}(())
1✔
85
    # Un-nest passed CartesianIndexes
86
    CartesianIndex{N}(index::CartesianIndex{N}) where {N} = index
4,795✔
87
    CartesianIndex(index::Union{Integer, CartesianIndex}...) = CartesianIndex(flatten(index))
39,172,037✔
88
    flatten(::Tuple{}) = ()
×
89
    flatten(I::Tuple{Any}) = Tuple(I[1])
78,595,085✔
90
    @inline flatten(I::Tuple) = (Tuple(I[1])..., flatten(tail(I))...)
40,064,130✔
91
    CartesianIndex(index::Tuple{Vararg{Union{Integer, CartesianIndex}}}) = CartesianIndex(index...)
1,108✔
92
    show(io::IO, i::CartesianIndex) = (print(io, "CartesianIndex"); show(io, i.I))
6,207✔
93

1,107✔
94
    # length
1,107✔
95
    length(::CartesianIndex{N}) where {N} = N
39,439,462✔
96
    length(::Type{CartesianIndex{N}}) where {N} = N
15,980✔
97

677,070✔
98
    # indexing
677,070✔
99
    getindex(index::CartesianIndex, i::Integer) = index.I[i]
62,354✔
100
    Base.get(A::AbstractArray, I::CartesianIndex, default) = get(A, I.I, default)
6,276✔
101
    eltype(::Type{T}) where {T<:CartesianIndex} = eltype(fieldtype(T, :I))
×
102

103
    # access to index tuple
104
    Tuple(index::CartesianIndex) = index.I
82,170,924✔
105

106
    Base.setindex(x::CartesianIndex,i,j) = CartesianIndex(Base.setindex(Tuple(x),i,j))
1✔
107

108
    # equality
109
    Base.:(==)(a::CartesianIndex{N}, b::CartesianIndex{N}) where N = a.I == b.I
2,444,669✔
110

410✔
111
    # zeros and ones
112
    zero(::CartesianIndex{N}) where {N} = zero(CartesianIndex{N})
383✔
113
    zero(::Type{CartesianIndex{N}}) where {N} = CartesianIndex(ntuple(Returns(0), Val(N)))
930✔
114
    oneunit(::CartesianIndex{N}) where {N} = oneunit(CartesianIndex{N})
231✔
115
    oneunit(::Type{CartesianIndex{N}}) where {N} = CartesianIndex(ntuple(Returns(1), Val(N)))
234✔
116

579✔
117
    # arithmetic, min/max
1,076✔
118
    @inline (-)(index::CartesianIndex{N}) where {N} =
219✔
119
        CartesianIndex{N}(map(-, index.I))
120
    @inline (+)(index1::CartesianIndex{N}, index2::CartesianIndex{N}) where {N} =
5,968✔
121
        CartesianIndex{N}(map(+, index1.I, index2.I))
756✔
122
    @inline (-)(index1::CartesianIndex{N}, index2::CartesianIndex{N}) where {N} =
3,108✔
123
        CartesianIndex{N}(map(-, index1.I, index2.I))
538✔
124
    @inline min(index1::CartesianIndex{N}, index2::CartesianIndex{N}) where {N} =
539✔
125
        CartesianIndex{N}(map(min, index1.I, index2.I))
538✔
126
    @inline max(index1::CartesianIndex{N}, index2::CartesianIndex{N}) where {N} =
271,917✔
127
        CartesianIndex{N}(map(max, index1.I, index2.I))
271,916✔
128

129
    @inline (*)(a::Integer, index::CartesianIndex{N}) where {N} = CartesianIndex{N}(map(x->a*x, index.I))
14,465✔
130
    @inline (*)(index::CartesianIndex, a::Integer) = *(a,index)
27,536✔
131

38,957✔
132
    # comparison
133
    isless(I1::CartesianIndex{N}, I2::CartesianIndex{N}) where {N} = isless(reverse(I1.I), reverse(I2.I))
28,199✔
134

135
    # conversions
136
    convert(::Type{T}, index::CartesianIndex{1}) where {T<:Number} = convert(T, index[1])
2✔
137
    convert(::Type{T}, index::CartesianIndex) where {T<:Tuple} = convert(T, index.I)
1✔
138

139
    # hashing
538✔
140
    const cartindexhash_seed = UInt == UInt64 ? 0xd60ca92f8284b8b0 : 0xf2ea7c2e
141
    function Base.hash(ci::CartesianIndex, h::UInt)
142
        h += cartindexhash_seed
28,284✔
143
        for i in ci.I
28,284✔
144
            h = hash(i, h)
56,566✔
145
        end
84,849✔
146
        return h
28,284✔
147
    end
148

149
    # nextind and prevind with CartesianIndex
150
    function Base.nextind(a::AbstractArray{<:Any,N}, i::CartesianIndex{N}) where {N}
1✔
151
        iter = CartesianIndices(axes(a))
510✔
152
        # might overflow
153
        I = inc(i.I, iter.indices)
764✔
154
        return I
510✔
155
    end
156
    function Base.prevind(a::AbstractArray{<:Any,N}, i::CartesianIndex{N}) where {N}
1✔
157
        iter = CartesianIndices(axes(a))
6✔
158
        # might underflow
159
        I = dec(i.I, iter.indices)
8✔
160
        return I
6✔
161
    end
162

163
    Base._ind2sub(t::Tuple, ind::CartesianIndex) = Tuple(ind)
×
164

165
    # Iteration over the elements of CartesianIndex cannot be supported until its length can be inferred,
15,320✔
166
    # see #23719
15,320✔
167
    Base.iterate(::CartesianIndex) =
15,321✔
168
        error("iteration is deliberately unsupported for CartesianIndex. Use `I` rather than `I...`, or use `Tuple(I)...`")
68,113✔
169

3,427,936✔
170
    # ranges are deliberately disabled to prevent ambiguities with the colon constructor
6,121,005✔
171
    Base.range_start_step_length(start::CartesianIndex, step::CartesianIndex, len::Integer) =
6,119,001✔
172
        error("range with a specified length is deliberately unsupported for CartesianIndex arguments."*
173
            " Use StepRangeLen($start, $step, $len) to construct this range")
15,320✔
174

175
    # show is special-cased to avoid the start:stop:step display,
176
    # which constructs a CartesianIndices
177
    # See #50784
178
    function show(io::IO, r::StepRangeLen{<:CartesianIndex})
15,322✔
179
        print(io, "StepRangeLen(", first(r), ", ",
2✔
180
                    step(r), ", ", length(r), ")")
181
    end
182

183
    # Iteration
184
    const OrdinalRangeInt = OrdinalRange{Int, Int}
185
    """
186
        CartesianIndices(sz::Dims) -> R
187
        CartesianIndices((istart:[istep:]istop, jstart:[jstep:]jstop, ...)) -> R
31✔
188

189
    Define a region `R` spanning a multidimensional rectangular range
20✔
190
    of integer indices. These are most commonly encountered in the
452✔
191
    context of iteration, where `for I in R ... end` will return
192
    [`CartesianIndex`](@ref) indices `I` equivalent to the nested loops
193

11✔
194
        for j = jstart:jstep:jstop
9,096✔
195
            for i = istart:istep:istop
8,331✔
196
                ...
197
            end
198
        end
199

4,432✔
200
    Consequently these can be useful for writing algorithms that
4,421✔
201
    work in arbitrary dimensions.
23,594✔
202

9,614✔
203
        CartesianIndices(A::AbstractArray) -> R
1,476✔
204

610✔
205
    As a convenience, constructing a `CartesianIndices` from an array makes a
1,846✔
206
    range of its indices.
3,011✔
207

1,863✔
208
    !!! compat "Julia 1.6"
1,854✔
209
        The step range method `CartesianIndices((istart:istep:istop, jstart:[jstep:]jstop, ...))`
2,401✔
210
        requires at least Julia 1.6.
839,767✔
211

841,507✔
212
    # Examples
840,495✔
213
    ```jldoctest
5,456✔
214
    julia> foreach(println, CartesianIndices((2, 2, 2)))
1,843✔
215
    CartesianIndex(1, 1, 1)
8,243✔
216
    CartesianIndex(2, 1, 1)
1,467✔
217
    CartesianIndex(1, 2, 1)
1,295✔
218
    CartesianIndex(2, 2, 1)
1,878✔
219
    CartesianIndex(1, 1, 2)
1,295✔
220
    CartesianIndex(2, 1, 2)
221
    CartesianIndex(1, 2, 2)
24✔
222
    CartesianIndex(2, 2, 2)
1,262✔
223

1,281✔
224
    julia> CartesianIndices(fill(1, (2,3)))
12,428✔
225
    CartesianIndices((2, 3))
144✔
226
    ```
9✔
227

900✔
228
    ## Conversion between linear and cartesian indices
14,475✔
229

15,816✔
230
    Linear index to cartesian index conversion exploits the fact that a
18✔
231
    `CartesianIndices` is an `AbstractArray` and can be indexed linearly:
232

1,259✔
233
    ```jldoctest
234
    julia> cartesian = CartesianIndices((1:3, 1:2))
235
    CartesianIndices((1:3, 1:2))
236

237
    julia> cartesian[4]
238
    CartesianIndex(1, 2)
239

240
    julia> cartesian = CartesianIndices((1:2:5, 1:2))
241
    CartesianIndices((1:2:5, 1:2))
242

243
    julia> cartesian[2, 2]
244
    CartesianIndex(3, 2)
245
    ```
246

247
    ## Broadcasting
248

249
    `CartesianIndices` support broadcasting arithmetic (+ and -) with a `CartesianIndex`.
250

251
    !!! compat "Julia 1.1"
252
        Broadcasting of CartesianIndices requires at least Julia 1.1.
253

254
    ```jldoctest
13✔
255
    julia> CIs = CartesianIndices((2:3, 5:6))
256
    CartesianIndices((2:3, 5:6))
257

258
    julia> CI = CartesianIndex(3, 4)
259
    CartesianIndex(3, 4)
260

261
    julia> CIs .+ CI
262
    CartesianIndices((5:6, 9:10))
263
    ```
264

265
    For cartesian to linear index conversion, see [`LinearIndices`](@ref).
266
    """
267
    struct CartesianIndices{N,R<:NTuple{N,OrdinalRangeInt}} <: AbstractArray{CartesianIndex{N},N}
268
        indices::R
675,610✔
269
    end
270

271
    CartesianIndices(::Tuple{}) = CartesianIndices{0,typeof(())}(())
×
272
    function CartesianIndices(inds::NTuple{N,OrdinalRange{<:Integer, <:Integer}}) where {N}
273
        indices = map(r->convert(OrdinalRangeInt, r), inds)
17,060✔
274
        CartesianIndices{N, typeof(indices)}(indices)
4,447✔
275
    end
276

277
    CartesianIndices(index::CartesianIndex) = CartesianIndices(index.I)
1✔
278
    CartesianIndices(inds::NTuple{N,Union{<:Integer,OrdinalRange{<:Integer}}}) where {N} =
2,000✔
279
        CartesianIndices(map(_convert2ind, inds))
280

281
    CartesianIndices(A::AbstractArray) = CartesianIndices(axes(A))
109,431✔
282

283
    _convert2ind(sz::Bool) = Base.OneTo(Int8(sz))
6✔
284
    _convert2ind(sz::Integer) = Base.oneto(sz)
3,998✔
285
    _convert2ind(sz::AbstractUnitRange) = first(sz):last(sz)
33✔
286
    _convert2ind(sz::OrdinalRange) = first(sz):step(sz):last(sz)
29✔
287

288
    function show(io::IO, iter::CartesianIndices)
4✔
289
        print(io, "CartesianIndices(")
4✔
290
        show(io, map(_xform_index, iter.indices))
4✔
291
        print(io, ")")
4✔
292
    end
293
    _xform_index(i) = i
1✔
294
    _xform_index(i::OneTo) = i.stop
2✔
295
    show(io::IO, ::MIME"text/plain", iter::CartesianIndices) = show(io, iter)
×
296

297
    """
298
        (:)(start::CartesianIndex, [step::CartesianIndex], stop::CartesianIndex)
299

300
    Construct [`CartesianIndices`](@ref) from two `CartesianIndex` and an optional step.
301

302
    !!! compat "Julia 1.1"
303
        This method requires at least Julia 1.1.
304

305
    !!! compat "Julia 1.6"
306
        The step range method start:step:stop requires at least Julia 1.6.
307

308
    # Examples
309
    ```jldoctest
310
    julia> I = CartesianIndex(2,1);
311

312
    julia> J = CartesianIndex(3,3);
313

314
    julia> I:J
315
    CartesianIndices((2:3, 1:3))
316

317
    julia> I:CartesianIndex(1, 2):J
318
    CartesianIndices((2:1:3, 1:2:3))
319
    ```
320
    """
321
    (:)(I::CartesianIndex{N}, J::CartesianIndex{N}) where N =
9✔
322
        CartesianIndices(map((i,j) -> i:j, Tuple(I), Tuple(J)))
13✔
323
    (:)(I::CartesianIndex{N}, S::CartesianIndex{N}, J::CartesianIndex{N}) where N =
12✔
324
        CartesianIndices(map((i,s,j) -> i:s:j, Tuple(I), Tuple(S), Tuple(J)))
46✔
325

326
    promote_rule(::Type{CartesianIndices{N,R1}}, ::Type{CartesianIndices{N,R2}}) where {N,R1,R2} =
4✔
327
        CartesianIndices{N,Base.indices_promote_type(R1,R2)}
328

329
    convert(::Type{Tuple{}}, R::CartesianIndices{0}) = ()
×
330
    for RT in (OrdinalRange{Int, Int}, StepRange{Int, Int}, AbstractUnitRange{Int})
331
        @eval convert(::Type{NTuple{N,$RT}}, R::CartesianIndices{N}) where {N} =
2✔
332
            map(x->convert($RT, x), R.indices)
4✔
333
    end
334
    convert(::Type{NTuple{N,AbstractUnitRange}}, R::CartesianIndices{N}) where {N} =
2✔
335
        convert(NTuple{N,AbstractUnitRange{Int}}, R)
336
    convert(::Type{NTuple{N,UnitRange{Int}}}, R::CartesianIndices{N}) where {N} =
1✔
337
        UnitRange{Int}.(convert(NTuple{N,AbstractUnitRange}, R))
338
    convert(::Type{NTuple{N,UnitRange}}, R::CartesianIndices{N}) where {N} =
1✔
339
        UnitRange.(convert(NTuple{N,AbstractUnitRange}, R))
340
    convert(::Type{Tuple{Vararg{AbstractUnitRange{Int}}}}, R::CartesianIndices{N}) where {N} =
×
341
        convert(NTuple{N,AbstractUnitRange{Int}}, R)
342
    convert(::Type{Tuple{Vararg{AbstractUnitRange}}}, R::CartesianIndices) =
×
343
        convert(Tuple{Vararg{AbstractUnitRange{Int}}}, R)
344
    convert(::Type{Tuple{Vararg{UnitRange{Int}}}}, R::CartesianIndices{N}) where {N} =
1✔
345
        convert(NTuple{N,UnitRange{Int}}, R)
346
    convert(::Type{Tuple{Vararg{UnitRange}}}, R::CartesianIndices) =
1✔
347
        convert(Tuple{Vararg{UnitRange{Int}}}, R)
348

349
    convert(::Type{CartesianIndices{N,R}}, inds::CartesianIndices{N}) where {N,R} =
2✔
350
        CartesianIndices(convert(R, inds.indices))::CartesianIndices{N,R}
351

352
    # equality
353
    Base.:(==)(a::CartesianIndices{N}, b::CartesianIndices{N}) where N =
1,241✔
354
        all(map(==, a.indices, b.indices))
355
    Base.:(==)(a::CartesianIndices, b::CartesianIndices) = false
×
356

357
    # AbstractArray implementation
358
    Base.axes(iter::CartesianIndices{N,R}) where {N,R} = map(Base.axes1, iter.indices)
4,104,805✔
359
    Base.has_offset_axes(iter::CartesianIndices) = Base.has_offset_axes(iter.indices...)
3✔
360
    @propagate_inbounds function isassigned(iter::CartesianIndices{N,R}, I::Vararg{Int, N}) where {N,R}
×
361
        for i in 1:N
×
362
            isassigned(iter.indices[i], I[i]) || return false
×
363
        end
×
364
        return true
×
365
    end
366

367
    # getindex for a 0D CartesianIndices is necessary for disambiguation
368
    @inline function Base.getindex(iter::CartesianIndices{0,R}) where {R}
1✔
369
        CartesianIndex()
9✔
370
    end
371
    @inline function Base.getindex(iter::CartesianIndices{N,R}, I::Vararg{Int, N}) where {N,R}
111✔
372
        # Eagerly do boundscheck before calculating each item of the CartesianIndex so that
373
        # we can pass `@inbounds` hint to inside the map and generates more efficient SIMD codes (#42115)
374
        @boundscheck checkbounds(iter, I...)
1,700,280✔
375
        index = map(iter.indices, I) do r, i
1,700,280✔
376
            @inbounds getindex(r, i)
4,656,594✔
377
        end
378
        CartesianIndex(index)
1,700,280✔
379
    end
380

381
    # CartesianIndices act as a multidimensional range, so cartesian indexing of CartesianIndices
382
    # with compatible dimensions may be seen as indexing into the component ranges.
383
    # This may use the special indexing behavior implemented for ranges to return another CartesianIndices
384
    @inline function Base.getindex(iter::CartesianIndices{N,R},
31✔
385
        I::Vararg{Union{OrdinalRange{<:Integer, <:Integer}, Colon}, N}) where {N,R}
386
        @boundscheck checkbounds(iter, I...)
2,054✔
387
        indices = map(iter.indices, I) do r, i
2,054✔
388
            @inbounds getindex(r, i)
2,112✔
389
        end
390
        CartesianIndices(indices)
2,054✔
391
    end
392
    @propagate_inbounds function Base.getindex(iter::CartesianIndices{N},
16✔
393
        C::CartesianIndices{N}) where {N}
394
        getindex(iter, C.indices...)
17✔
395
    end
396
    @inline Base.getindex(iter::CartesianIndices{0}, ::CartesianIndices{0}) = iter
1✔
397

398
    # If dimensions permit, we may index into a CartesianIndices directly instead of constructing a SubArray wrapper
399
    @propagate_inbounds function Base.view(c::CartesianIndices{N}, r::Vararg{Union{OrdinalRange{<:Integer, <:Integer}, Colon},N}) where {N}
4✔
400
        getindex(c, r...)
2,006✔
401
    end
402
    @propagate_inbounds function Base.view(c::CartesianIndices{N}, C::CartesianIndices{N}) where {N}
403
        getindex(c, C)
1✔
404
    end
405

406
    eachindex(::IndexCartesian, A::AbstractArray) = CartesianIndices(axes(A))
94,564✔
407

408
    @inline function eachindex(::IndexCartesian, A::AbstractArray, B::AbstractArray...)
1✔
409
        axsA = axes(A)
4✔
410
        Base._all_match_first(axes, axsA, B...) || Base.throw_eachindex_mismatch_indices(IndexCartesian(), axes(A), axes.(B)...)
5✔
411
        CartesianIndices(axsA)
3✔
412
    end
413

414
    @inline function iterate(iter::CartesianIndices)
1,219✔
415
        iterfirst = first(iter)
264,947✔
416
        if !all(map(in, iterfirst.I, iter.indices))
268,647✔
417
            return nothing
93✔
418
        end
419
        iterfirst, iterfirst
264,852✔
420
    end
421
    @inline function iterate(iter::CartesianIndices, state)
43,101✔
422
        valid, I = __inc(state.I, iter.indices)
81,885,271✔
423
        valid || return nothing
80,870,660✔
424
        return CartesianIndex(I...), CartesianIndex(I...)
80,354,190✔
425
    end
426

427
    # increment & carry
428
    @inline function inc(state, indices)
429
        _, I = __inc(state, indices)
704,616✔
430
        return CartesianIndex(I...)
667,003✔
431
    end
432

433
    # Unlike ordinary ranges, CartesianIndices continues the iteration in the next column when the
434
    # current column is consumed. The implementation is written recursively to achieve this.
435
    # `iterate` returns `Union{Nothing, Tuple}`, we explicitly pass a `valid` flag to eliminate
436
    # the type instability inside the core `__inc` logic, and this gives better runtime performance.
437
    __inc(::Tuple{}, ::Tuple{}) = false, ()
8✔
438
    @inline function __inc(state::Tuple{Int}, indices::Tuple{OrdinalRangeInt})
439
        rng = indices[1]
1,887,360✔
440
        I = state[1] + step(rng)
1,906,832✔
441
        valid = state[1] != last(rng)
1,906,832✔
442
        return valid, (I,)
1,887,360✔
443
    end
444
    @inline function __inc(state::Tuple{Int,Int,Vararg{Int}}, indices::Tuple{OrdinalRangeInt,OrdinalRangeInt,Vararg{OrdinalRangeInt}})
445
        rng = indices[1]
80,783,295✔
446
        I = state[1] + step(rng)
80,783,295✔
447
        if state[1] != last(rng)
80,783,295✔
448
            return true, (I, tail(state)...)
79,372,596✔
449
        end
450
        valid, I = __inc(tail(state), tail(indices))
1,510,937✔
451
        return valid, (first(rng), I...)
1,410,699✔
452
    end
453

454
    # 0-d cartesian ranges are special-cased to iterate once and only once
455
    iterate(iter::CartesianIndices{0}, done=false) = done ? nothing : (CartesianIndex(), true)
1,477✔
456

457
    size(iter::CartesianIndices) = map(length, iter.indices)
128,701✔
458

459
    length(iter::CartesianIndices) = prod(size(iter))
127,483✔
460

461
    # make CartesianIndices a multidimensional range
462
    Base.step(iter::CartesianIndices) = CartesianIndex(map(step, iter.indices))
9✔
463

464
    first(iter::CartesianIndices) = CartesianIndex(map(first, iter.indices))
408,166✔
465
    last(iter::CartesianIndices)  = CartesianIndex(map(last, iter.indices))
9,029✔
466

467
    # When used as indices themselves, CartesianIndices can simply become its tuple of ranges
468
    @inline function to_indices(A, inds, I::Tuple{CartesianIndices{N}, Vararg}) where N
469
        _, indstail = split(inds, Val(N))
1,799✔
470
        (map(Fix1(to_index, A), I[1].indices)..., to_indices(A, indstail, tail(I))...)
1,799✔
471
    end
472
    # but preserve CartesianIndices{0} as they consume a dimension.
473
    @inline to_indices(A, inds, I::Tuple{CartesianIndices{0}, Vararg}) =
29✔
474
        (first(I), to_indices(A, inds, tail(I))...)
475

476
    @inline in(i::CartesianIndex, r::CartesianIndices) = false
×
477
    @inline in(i::CartesianIndex{N}, r::CartesianIndices{N}) where {N} = all(map(in, i.I, r.indices))
43✔
478

479
    simd_outer_range(iter::CartesianIndices{0}) = iter
5✔
480
    function simd_outer_range(iter::CartesianIndices)
1✔
481
        CartesianIndices(tail(iter.indices))
156,499✔
482
    end
483

484
    simd_inner_length(iter::CartesianIndices{0}, ::CartesianIndex) = 1
×
485
    simd_inner_length(iter::CartesianIndices, I::CartesianIndex) = Base.length(iter.indices[1])
1,076,999✔
486

487
    simd_index(iter::CartesianIndices{0}, ::CartesianIndex, I1::Int) = first(iter)
5✔
488
    @propagate_inbounds simd_index(iter::CartesianIndices, Ilast::CartesianIndex, I1::Int) =
39,172,036✔
489
        CartesianIndex(iter.indices[1][I1+firstindex(iter.indices[1])], Ilast)
490

491
    # Split out the first N elements of a tuple
492
    @inline function split(t, V::Val)
493
        ref = ntuple(Returns(true), V)  # create a reference tuple of length N
238,222,281✔
494
        _split1(t, ref), _splitrest(t, ref)
238,222,281✔
495
    end
496
    @inline _split1(t, ref) = (t[1], _split1(tail(t), tail(ref))...)
80,029,302✔
497
    @inline _splitrest(t, ref) = _splitrest(tail(t), tail(ref))
81,006,562✔
498
    # exit either when we've exhausted the input or reference tuple
499
    _split1(::Tuple{}, ::Tuple{}) = ()
×
500
    _split1(::Tuple{}, ref) = ()
198,708,738✔
501
    _split1(t, ::Tuple{}) = ()
77,962✔
502
    _splitrest(::Tuple{}, ::Tuple{}) = ()
×
503
    _splitrest(t, ::Tuple{}) = t
1,055,233✔
504
    _splitrest(::Tuple{}, ref) = ()
198,709,188✔
505

506
    @inline function split(I::CartesianIndex, V::Val)
×
507
        i, j = split(I.I, V)
×
508
        CartesianIndex(i), CartesianIndex(j)
×
509
    end
510
    function split(R::CartesianIndices, V::Val)
×
511
        i, j = split(R.indices, V)
×
512
        CartesianIndices(i), CartesianIndices(j)
×
513
    end
514

515
    # reversed CartesianIndices iteration
516
    @inline function Base._reverse(iter::CartesianIndices, ::Colon)
517
        CartesianIndices(reverse.(iter.indices))
7✔
518
    end
519

520
    Base.@constprop :aggressive function Base._reverse(iter::CartesianIndices, dim::Integer)
4✔
521
        1 <= dim <= ndims(iter) || throw(ArgumentError(Base.LazyString("invalid dimension ", dim, " in reverse")))
7✔
522
        ndims(iter) == 1 && return Base._reverse(iter, :)
3✔
523
        indices = iter.indices
3✔
524
        return CartesianIndices(Base.setindex(indices, reverse(indices[dim]), dim))
4✔
525
    end
526

527
    Base.@constprop :aggressive function Base._reverse(iter::CartesianIndices, dims::Tuple{Vararg{Integer}})
5✔
528
        indices = iter.indices
7✔
529
        # use `sum` to force const fold
530
        dimrev = ntuple(i -> sum(==(i), dims; init = 0) == 1, Val(length(indices)))
14✔
531
        length(dims) == sum(dimrev) || throw(ArgumentError(Base.LazyString("invalid dimensions ", dims, " in reverse")))
10✔
532
        length(dims) == length(indices) && return Base._reverse(iter, :)
4✔
533
        indices′ = map((i, f) -> f ? (@noinline reverse(i)) : i, indices, dimrev)
16✔
534
        return CartesianIndices(indices′)
4✔
535
    end
536

537
    # fix ambiguity with array.jl:
538
    Base._reverse(iter::CartesianIndices{1}, dims::Tuple{Integer}) =
×
539
        Base._reverse(iter, first(dims))
540

541
    @inline function iterate(r::Reverse{<:CartesianIndices})
542
        iterfirst = last(r.itr)
13✔
543
        if !all(map(in, iterfirst.I, r.itr.indices))
15✔
544
            return nothing
×
545
        end
546
        iterfirst, iterfirst
13✔
547
    end
548
    @inline function iterate(r::Reverse{<:CartesianIndices}, state)
8✔
549
        valid, I = __dec(state.I, r.itr.indices)
280✔
550
        valid || return nothing
241✔
551
        return CartesianIndex(I...), CartesianIndex(I...)
207✔
552
    end
553

554
    # decrement & carry
555
    @inline function dec(state, indices)
556
        _, I = __dec(state, indices)
123,821✔
557
        return CartesianIndex(I...)
117,912✔
558
    end
559

560
    # decrement post check to avoid integer overflow
561
    @inline __dec(::Tuple{}, ::Tuple{}) = false, ()
×
562
    @inline function __dec(state::Tuple{Int}, indices::Tuple{OrdinalRangeInt})
563
        rng = indices[1]
5,963✔
564
        I = state[1] - step(rng)
5,963✔
565
        valid = state[1] != first(rng)
5,963✔
566
        return valid, (I,)
5,963✔
567
    end
568
    @inline function __dec(state::Tuple{Int,Int,Vararg{Int}}, indices::Tuple{OrdinalRangeInt,OrdinalRangeInt,Vararg{OrdinalRangeInt}})
569
        rng = indices[1]
118,150✔
570
        I = state[1] - step(rng)
118,150✔
571
        if state[1] != first(rng)
118,150✔
572
            return true, (I, tail(state)...)
112,173✔
573
        end
574
        valid, I = __dec(tail(state), tail(indices))
5,989✔
575
        return valid, (last(rng), I...)
5,977✔
576
    end
577

578
    # 0-d cartesian ranges are special-cased to iterate once and only once
579
    iterate(iter::Reverse{<:CartesianIndices{0}}, state=false) = state ? nothing : (CartesianIndex(), true)
×
580

581
    function Base.LinearIndices(inds::CartesianIndices{N,R}) where {N,R<:NTuple{N, AbstractUnitRange}}
5✔
582
        LinearIndices{N,R}(inds.indices)
1,523✔
583
    end
584
    function Base.LinearIndices(inds::CartesianIndices)
6✔
585
        indices = inds.indices
6✔
586
        if all(x->step(x)==1, indices)
17✔
587
            indices = map(rng->first(rng):last(rng), indices)
3✔
588
            LinearIndices{length(indices), typeof(indices)}(indices)
1✔
589
        else
590
            # Given the fact that StepRange 1:2:4 === 1:2:3, we lost the original size information
591
            # and thus cannot calculate the correct linear indices when the steps are not 1.
592
            throw(ArgumentError("LinearIndices for $(typeof(inds)) with non-1 step size is not yet supported."))
5✔
593
        end
594
    end
595

596
    # This is currently needed because converting to LinearIndices is only available when steps are
597
    # all 1
598
    # NOTE: this is only a temporary patch and could be possibly removed when StepRange support to
599
    # LinearIndices is done
600
    function Base.collect(inds::CartesianIndices{N, R}) where {N,R<:NTuple{N, AbstractUnitRange}}
770✔
601
        Base._collect_indices(axes(inds), inds)
2,271✔
602
    end
603
    function Base.collect(inds::CartesianIndices)
515✔
604
        dest = Array{eltype(inds), ndims(inds)}(undef, size(inds))
1,030✔
605
        i = 0
515✔
606
        @inbounds for a in inds
1,030✔
607
            dest[i+=1] = a
3,413✔
608
        end
3,928✔
609
        dest
515✔
610
    end
611

612
    # array operations
613
    Base.intersect(a::CartesianIndices{N}, b::CartesianIndices{N}) where N =
2✔
614
        CartesianIndices(intersect.(a.indices, b.indices))
615

616
    # Views of reshaped CartesianIndices are used for partitions — ensure these are fast
617
    const CartesianPartition{T<:CartesianIndex, P<:CartesianIndices, R<:ReshapedArray{T,1,P}} = SubArray{T,1,R,<:Tuple{AbstractUnitRange{Int}},false}
618
    eltype(::Type{PartitionIterator{T}}) where {T<:ReshapedArrayLF} = SubArray{eltype(T), 1, T, Tuple{UnitRange{Int}}, true}
×
619
    eltype(::Type{PartitionIterator{T}}) where {T<:ReshapedArray} = SubArray{eltype(T), 1, T, Tuple{UnitRange{Int}}, false}
4✔
620
    Iterators.IteratorEltype(::Type{<:PartitionIterator{T}}) where {T<:ReshapedArray} = Iterators.IteratorEltype(T)
1✔
621

622
    eltype(::Type{PartitionIterator{T}}) where {T<:OneTo} = UnitRange{eltype(T)}
4✔
623
    eltype(::Type{PartitionIterator{T}}) where {T<:Union{UnitRange, StepRange, StepRangeLen, LinRange}} = T
26✔
624
    Iterators.IteratorEltype(::Type{<:PartitionIterator{T}}) where {T<:Union{OneTo, UnitRange, StepRange, StepRangeLen, LinRange}} = Iterators.IteratorEltype(T)
15✔
625

626
    @inline function iterate(iter::CartesianPartition)
627
        isempty(iter) && return nothing
82,514✔
628
        f = first(iter)
82,514✔
629
        return (f, (f, 1))
82,514✔
630
    end
631
    @inline function iterate(iter::CartesianPartition, (state, n))
632
        n >= length(iter) && return nothing
848,922✔
633
        I = IteratorsMD.inc(state.I, iter.parent.parent.indices)
681,498✔
634
        return I, (I, n+1)
648,502✔
635
    end
636

637
    @inline function simd_outer_range(iter::CartesianPartition)
638
        # In general, the Cartesian Partition might start and stop in the middle of the outer
639
        # dimensions — thus the outer range of a CartesianPartition is itself a
640
        # CartesianPartition.
641
        mi = iter.parent.mi
117,906✔
642
        ci = iter.parent.parent
117,906✔
643
        ax, ax1 = axes(ci), Base.axes1(ci)
117,906✔
644
        subs = Base.ind2sub_rs(ax, mi, first(iter.indices[1]))
117,906✔
645
        vl, fl = Base._sub2ind(tail(ax), tail(subs)...), subs[1]
117,906✔
646
        vr, fr = divrem(last(iter.indices[1]) - 1, mi[end]) .+ (1, first(ax1))
117,906✔
647
        oci = CartesianIndices(tail(ci.indices))
117,906✔
648
        # A fake CartesianPartition to reuse the outer iterate fallback
649
        outer = @inbounds view(ReshapedArray(oci, (length(oci),), mi), vl:vr)
117,906✔
650
        init = @inbounds dec(oci[tail(subs)...].I, oci.indices) # real init state
123,813✔
651
        # Use Generator to make inner loop branchless
652
        @inline function skip_len_I(i::Int, I::CartesianIndex)
117,906✔
653
            l = i == 1 ? fl : first(ax1)
179,586✔
654
            r = i == length(outer) ? fr : last(ax1)
179,586✔
655
            l - first(ax1), r - l + 1, I
153,936✔
656
        end
657
        (skip_len_I(i, I) for (i, I) in Iterators.enumerate(Iterators.rest(outer, (init, 0))))
117,906✔
658
    end
659
    @inline function simd_outer_range(iter::CartesianPartition{CartesianIndex{2}})
660
        # But for two-dimensional Partitions the above is just a simple one-dimensional range
661
        # over the second dimension; we don't need to worry about non-rectangular staggers in
662
        # higher dimensions.
663
        mi = iter.parent.mi
5,865✔
664
        ci = iter.parent.parent
5,865✔
665
        ax, ax1 = axes(ci), Base.axes1(ci)
5,865✔
666
        fl, vl = Base.ind2sub_rs(ax, mi, first(iter.indices[1]))
5,865✔
667
        fr, vr = Base.ind2sub_rs(ax, mi, last(iter.indices[1]))
5,865✔
668
        outer = @inbounds CartesianIndices((ci.indices[2][vl:vr],))
6,021✔
669
        # Use Generator to make inner loop branchless
670
        @inline function skip_len_I(I::CartesianIndex{1})
5,865✔
671
            l = I == first(outer) ? fl : first(ax1)
10,935✔
672
            r = I == last(outer) ? fr : last(ax1)
10,935✔
673
            l - first(ax1), r - l + 1, I
7,908✔
674
        end
675
        (skip_len_I(I) for I in outer)
5,865✔
676
    end
677
    @inline simd_inner_length(iter::CartesianPartition, (_, len, _)::Tuple{Int,Int,CartesianIndex}) = len
161,844✔
678
    @propagate_inbounds simd_index(iter::CartesianPartition, (skip, _, I)::Tuple{Int,Int,CartesianIndex}, n::Int) =
577,080✔
679
        simd_index(iter.parent.parent, I, n + skip)
680
end  # IteratorsMD
681

682

683
using .IteratorsMD
684

685
## Bounds-checking with CartesianIndex
686
# Disallow linear indexing with CartesianIndex
687
@inline checkbounds(::Type{Bool}, A::AbstractArray, i::CartesianIndex) =
2,244✔
688
    checkbounds_indices(Bool, axes(A), (i,))
689
# Here we try to consume N of the indices (if there are that many available)
690
@inline function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{CartesianIndex,Vararg})
2✔
691
    inds1, rest = IteratorsMD.split(inds, Val(length(I[1])))
39,433,185✔
692
    checkindex(Bool, inds1, I[1]) & checkbounds_indices(Bool, rest, tail(I))
39,433,185✔
693
end
694
@inline checkindex(::Type{Bool}, inds::Tuple, I::CartesianIndex) =
39,442,545✔
695
    checkbounds_indices(Bool, inds, I.I)
696

697
# Indexing into Array with mixtures of Integers and CartesianIndices is
698
# extremely performance-sensitive. While the abstract fallbacks support this,
699
# codegen has extra support for SIMDification that sub2ind doesn't (yet) support
700
@propagate_inbounds getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...) =
75,068,385✔
701
    A[to_indices(A, (i1, I...))...]
702
@propagate_inbounds setindex!(A::Array, v, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...) =
105,012,100✔
703
    (A[to_indices(A, (i1, I...))...] = v; A)
44,710,896✔
704

705
## Bounds-checking with arrays of CartesianIndex{N}
706
# Disallow linear indexing with an array of CartesianIndex{N}
707
@inline checkbounds(::Type{Bool}, A::AbstractArray, i::AbstractArray{CartesianIndex{N}}) where {N} =
4,037✔
708
    checkbounds_indices(Bool, axes(A), (i,))
709
# Here we try to consume N of the indices (if there are that many available)
710
@inline function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{AbstractArray{CartesianIndex{N}},Vararg}) where N
3✔
711
    inds1, rest = IteratorsMD.split(inds, Val(N))
2,186✔
712
    checkindex(Bool, inds1, I[1]) & checkbounds_indices(Bool, rest, tail(I))
4,221✔
713
end
714
@inline checkindex(::Type{Bool}, inds::Tuple, I::CartesianIndices) =
40✔
715
    checkbounds_indices(Bool, inds, I.indices)
716

717
# combined count of all indices, including CartesianIndex and
718
# AbstractArray{CartesianIndex}
719
# rather than returning N, it returns an NTuple{N,Bool} so the result is inferable
720
@inline index_ndims(i1, I...) = (true, index_ndims(I...)...)
5,064,647✔
721
@inline function index_ndims(i1::CartesianIndex, I...)
×
722
    (map(Returns(true), i1.I)..., index_ndims(I...)...)
×
723
end
724
@inline function index_ndims(i1::AbstractArray{CartesianIndex{N}}, I...) where N
12✔
725
    (ntuple(Returns(true), Val(N))..., index_ndims(I...)...)
633✔
726
end
727
index_ndims() = ()
×
728

729
# combined dimensionality of all indices
730
# rather than returning N, it returns an NTuple{N,Bool} so the result is inferable
731
@inline index_dimsum(i1, I...) = (index_dimsum(I...)...,)
720,448✔
732
@inline index_dimsum(::Colon, I...) = (true, index_dimsum(I...)...)
×
733
@inline index_dimsum(::AbstractArray{Bool}, I...) = (true, index_dimsum(I...)...)
×
734
@inline function index_dimsum(::AbstractArray{<:Any,N}, I...) where N
735
    (ntuple(Returns(true), Val(N))..., index_dimsum(I...)...)
1,174,330✔
736
end
737
index_dimsum() = ()
×
738

739
# Recursively compute the lengths of a list of indices, without dropping scalars
740
index_lengths() = ()
114,398✔
741
@inline index_lengths(::Real, rest...) = (1, index_lengths(rest...)...)
32,418✔
742
@inline index_lengths(A::AbstractArray, rest...) = (length(A), index_lengths(rest...)...)
123,002✔
743

744
# shape of array to create for getindex() with indices I, dropping scalars
745
# returns a Tuple{Vararg{AbstractUnitRange}} of indices
746
index_shape() = ()
×
747
@inline index_shape(::Real, rest...) = index_shape(rest...)
24,246✔
748
@inline index_shape(A::AbstractArray, rest...) = (axes(A)..., index_shape(rest...)...)
315,322✔
749

750
"""
751
    LogicalIndex(mask)
752

753
The `LogicalIndex` type is a special vector that simply contains all indices I
754
where `mask[I]` is true. This specialized type does not support indexing
755
directly as doing so would require O(n) lookup time. `AbstractArray{Bool}` are
756
wrapped with `LogicalIndex` upon calling [`to_indices`](@ref).
757
"""
758
struct LogicalIndex{T, A<:AbstractArray{Bool}} <: AbstractVector{T}
759
    mask::A
760
    sum::Int
761
    LogicalIndex{T,A}(mask::A) where {T,A<:AbstractArray{Bool}} = new(mask, count(mask))
84,609✔
762
end
763
LogicalIndex(mask::AbstractVector{Bool}) = LogicalIndex{Int, typeof(mask)}(mask)
4,092✔
764
LogicalIndex(mask::AbstractArray{Bool, N}) where {N} = LogicalIndex{CartesianIndex{N}, typeof(mask)}(mask)
46✔
765
LogicalIndex{Int}(mask::AbstractArray) = LogicalIndex{Int, typeof(mask)}(mask)
80,471✔
766
size(L::LogicalIndex) = (L.sum,)
40,192✔
767
length(L::LogicalIndex) = L.sum
1,409✔
768
collect(L::LogicalIndex) = [i for i in L]
473✔
769
show(io::IO, r::LogicalIndex) = print(io,collect(r))
×
770
print_array(io::IO, X::LogicalIndex) = print_array(io, collect(X))
×
771
# Iteration over LogicalIndex is very performance-critical, but it also must
772
# support arbitrary AbstractArray{Bool}s with both Int and CartesianIndex.
773
# Thus the iteration state contains an index iterator and its state. We also
774
# keep track of the count of elements since we already know how many there
775
# should be -- this way we don't need to look at future indices to check done.
776
@inline function iterate(L::LogicalIndex{Int})
777
    r = LinearIndices(L.mask)
76✔
778
    iterate(L, (1, r))
133✔
779
end
780
@inline function iterate(L::LogicalIndex{<:CartesianIndex})
×
781
    r = CartesianIndices(axes(L.mask))
×
782
    iterate(L, (1, r))
×
783
end
784
@propagate_inbounds function iterate(L::LogicalIndex, s)
785
    # We're looking for the n-th true element, using iterator r at state i
786
    n = s[1]
897✔
787
    n > length(L) && return nothing
897✔
788
    #unroll once to help inference, cf issue #29418
789
    idx, i = iterate(tail(s)...)::Tuple{Any,Any}
1,454✔
790
    s = (n+1, s[2], i)
821✔
791
    L.mask[idx] && return (idx, s)
826✔
792
    while true
626✔
793
        idx, i = iterate(tail(s)...)::Tuple{Any,Any}
1,252✔
794
        s = (n+1, s[2], i)
626✔
795
        L.mask[idx] && return (idx, s)
631✔
796
    end
266✔
797
end
798
# When wrapping a BitArray, lean heavily upon its internals.
799
@inline function iterate(L::LogicalIndex{Int,<:BitArray})
800
    L.sum == 0 && return nothing
50,410✔
801
    Bc = L.mask.chunks
49,904✔
802
    return iterate(L, (1, 1, (), @inbounds Bc[1]))
49,904✔
803
end
804
@inline function iterate(L::LogicalIndex{<:CartesianIndex,<:BitArray})
805
    L.sum == 0 && return nothing
38✔
806
    Bc = L.mask.chunks
28✔
807
    irest = ntuple(one, ndims(L.mask)-1)
28✔
808
    return iterate(L, (1, 1, irest, @inbounds Bc[1]))
28✔
809
end
810
@inline function iterate(L::LogicalIndex{<:Any,<:BitArray}, (i1, Bi, irest, c))
811
    Bc = L.mask.chunks
2,011,564✔
812
    while c == 0
2,056,873✔
813
        Bi >= length(Bc) && return nothing
95,241✔
814
        i1 += 64
45,309✔
815
        @inbounds c = Bc[Bi+=1]
45,309✔
816
    end
45,309✔
817
    tz = trailing_zeros(c)
1,961,632✔
818
    c = _blsr(c)
1,961,632✔
819
    i1, irest = _overflowind(i1 + tz, irest, size(L.mask))
1,961,632✔
820
    return eltype(L)(i1, irest...), (i1 - tz, Bi, irest, c)
1,961,632✔
821
end
822

823
## Boundscheck for Logicalindex
824
# LogicalIndex: map all calls to mask
825
checkbounds(::Type{Bool}, A::AbstractArray, i::LogicalIndex) = checkbounds(Bool, A, i.mask)
36,379✔
826
# `checkbounds_indices` has been handled via `I::AbstractArray` fallback
827
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::LogicalIndex) = checkindex(Bool, inds, i.mask)
3,824✔
828
checkindex(::Type{Bool}, inds::Tuple, i::LogicalIndex) = checkindex(Bool, inds, i.mask)
25✔
829

830
## Boundscheck for AbstractArray{Bool}
831
# Disallow linear indexing with AbstractArray{Bool}
832
checkbounds(::Type{Bool}, A::AbstractArray, i::AbstractArray{Bool}) =
55✔
833
    checkbounds_indices(Bool, axes(A), (i,))
834
# But allow linear indexing with AbstractVector{Bool}
835
checkbounds(::Type{Bool}, A::AbstractArray, i::AbstractVector{Bool}) =
36,411✔
836
    checkindex(Bool, eachindex(IndexLinear(), A), i)
837
@inline function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{AbstractArray{Bool},Vararg})
8✔
838
    inds1, rest = IteratorsMD.split(inds, Val(ndims(I[1])))
111✔
839
    checkindex(Bool, inds1, I[1]) & checkbounds_indices(Bool, rest, tail(I))
117✔
840
end
841
checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractVector{Bool}) = axes1(I) == inds
40,118✔
842
checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractRange{Bool}) = axes1(I) == inds
117✔
843
checkindex(::Type{Bool}, inds::Tuple, I::AbstractArray{Bool}) = _check_boolean_axes(inds, axes(I))
139✔
844
_check_boolean_axes(inds::Tuple, axes::Tuple) = (inds[1] == axes[1]) & _check_boolean_axes(tail(inds), tail(axes))
269✔
845
_check_boolean_axes(::Tuple{}, axes::Tuple) = all(==(OneTo(1)), axes)
139✔
846

847
ensure_indexable(I::Tuple{}) = ()
×
848
@inline ensure_indexable(I::Tuple{Any, Vararg{Any}}) = (I[1], ensure_indexable(tail(I))...)
32,143,412✔
849
@inline ensure_indexable(I::Tuple{LogicalIndex, Vararg{Any}}) = (collect(I[1]), ensure_indexable(tail(I))...)
473✔
850

851
# In simple cases, we know that we don't need to use axes(A). Optimize those
852
# until Julia gets smart enough to elide the call on its own:
853
@inline to_indices(A, I::Tuple{Vararg{Union{Integer, CartesianIndex}}}) = to_indices(A, (), I)
199,594,259✔
854
# But some index types require more context spanning multiple indices
855
# CartesianIndex is unfolded outside the inner to_indices for better inference
856
@inline function to_indices(A, inds, I::Tuple{CartesianIndex{N}, Vararg}) where N
75✔
857
    _, indstail = IteratorsMD.split(inds, Val(N))
199,604,124✔
858
    (map(Fix1(to_index, A), I[1].I)..., to_indices(A, indstail, tail(I))...)
199,604,124✔
859
end
860
# For arrays of CartesianIndex, we just skip the appropriate number of inds
861
@inline function to_indices(A, inds, I::Tuple{AbstractArray{CartesianIndex{N}}, Vararg}) where N
5✔
862
    _, indstail = IteratorsMD.split(inds, Val(N))
2,117✔
863
    (to_index(A, I[1]), to_indices(A, indstail, tail(I))...)
2,117✔
864
end
865
# And boolean arrays behave similarly; they also skip their number of dimensions
866
@inline function to_indices(A, inds, I::Tuple{AbstractArray{Bool, N}, Vararg}) where N
867
    _, indstail = IteratorsMD.split(inds, Val(N))
121✔
868
    (to_index(A, I[1]), to_indices(A, indstail, tail(I))...)
4,066✔
869
end
870
# As an optimization, we allow the only `AbstractArray{Bool}` to be linear-iterated
871
@inline to_indices(A, I::Tuple{AbstractArray{Bool}}) = (_maybe_linear_logical_index(IndexStyle(A), A, I[1]),)
80,497✔
872
_maybe_linear_logical_index(::IndexStyle, A, i) = to_index(A, i)
26✔
873
_maybe_linear_logical_index(::IndexLinear, A, i) = LogicalIndex{Int}(i)
80,471✔
874

875
# Colons get converted to slices by `uncolon`
876
@inline to_indices(A, inds, I::Tuple{Colon, Vararg}) =
572,761✔
877
    (uncolon(inds), to_indices(A, Base.safe_tail(inds), tail(I))...)
878

879
uncolon(::Tuple{}) = Slice(OneTo(1))
402✔
880
uncolon(inds::Tuple) = Slice(inds[1])
572,259✔
881

882
"""
883
    _prechecked_iterate(iter[, state])
884

885
Internal function used to eliminate the dead branch in `iterate`.
886
Fallback to `iterate` by default, but optimized for indices type in `Base`.
887
"""
888
@propagate_inbounds _prechecked_iterate(iter) = iterate(iter)
×
889
@propagate_inbounds _prechecked_iterate(iter, state) = iterate(iter, state)
×
890

891
_prechecked_iterate(iter::AbstractUnitRange, i = first(iter)) = i, convert(eltype(iter), i + step(iter))
6,936,018✔
892
_prechecked_iterate(iter::LinearIndices, i = first(iter)) = i, i + 1
14✔
893
_prechecked_iterate(iter::CartesianIndices) = first(iter), first(iter)
1,020✔
894
function _prechecked_iterate(iter::CartesianIndices, i)
895
    i′ = IteratorsMD.inc(i.I, iter.indices)
22,354✔
896
    return i′, i′
17,991✔
897
end
898
_prechecked_iterate(iter::SCartesianIndices2) = first(iter), first(iter)
1✔
899
function _prechecked_iterate(iter::SCartesianIndices2{K}, (;i, j)) where {K}
900
    I = i < K ? SCartesianIndex2{K}(i + 1, j) : SCartesianIndex2{K}(1, j + 1)
12✔
901
    return I, I
9✔
902
end
903

904
### From abstractarray.jl: Internal multidimensional indexing definitions ###
905
getindex(x::Union{Number,AbstractChar}, ::CartesianIndex{0}) = x
×
906
getindex(t::Tuple,  i::CartesianIndex{1}) = getindex(t, i.I[1])
×
907

908
# These are not defined on directly on getindex to avoid
909
# ambiguities for AbstractArray subtypes. See the note in abstractarray.jl
910

911
@inline function _getindex(l::IndexStyle, A::AbstractArray, I::Union{Real, AbstractArray}...)
3,169✔
912
    @boundscheck checkbounds(A, I...)
290,402✔
913
    return _unsafe_getindex(l, _maybe_reshape(l, A, I...), I...)
569,878✔
914
end
915
# But we can speed up IndexCartesian arrays by reshaping them to the appropriate dimensionality:
916
_maybe_reshape(::IndexLinear, A::AbstractArray, I...) = A
187,211✔
917
_maybe_reshape(::IndexCartesian, A::AbstractVector, I...) = A
488✔
918
@inline _maybe_reshape(::IndexCartesian, A::AbstractArray, I...) = __maybe_reshape(A, index_ndims(I...))
2,554✔
919
@inline __maybe_reshape(A::AbstractArray{T,N}, ::NTuple{N,Any}) where {T,N} = A
2,488✔
920
@inline __maybe_reshape(A::AbstractArray, ::NTuple{N,Any}) where {N} = reshape(A, Val(N))
66✔
921

922
function _unsafe_getindex(::IndexStyle, A::AbstractArray, I::Vararg{Union{Real, AbstractArray}, N}) where N
188,284✔
923
    # This is specifically not inlined to prevent excessive allocations in type unstable code
924
    shape = index_shape(I...)
290,339✔
925
    dest = similar(A, shape)
493,573✔
926
    map(length, axes(dest)) == map(length, shape) || throw_checksize_error(dest, shape)
290,339✔
927
    _unsafe_getindex!(dest, A, I...) # usually a generated function, don't allow it to impact inference result
3,298,293✔
928
    return dest
290,338✔
929
end
930

931
function _generate_unsafe_getindex!_body(N::Int)
319✔
932
    quote
319✔
933
        @inline
934
        D = eachindex(dest)
935
        Dy = _prechecked_iterate(D)
936
        @inbounds @nloops $N j d->I[d] begin
937
            (idx, state) = Dy::NTuple{2,Any}
938
            dest[idx] = @ncall $N getindex src j
939
            Dy = _prechecked_iterate(D, state)
940
        end
941
        return dest
942
    end
943
end
944

945
# Always index with the exactly indices provided.
946
@generated function _unsafe_getindex!(dest::AbstractArray, src::AbstractArray, I::Vararg{Union{Real, AbstractArray}, N}) where N
29,750✔
947
    _generate_unsafe_getindex!_body(N)
319✔
948
end
949

950
# manually written-out specializations for 1 and 2 arguments to save compile time
951
@eval function _unsafe_getindex!(dest::AbstractArray, src::AbstractArray, I::Vararg{Union{Real, AbstractArray},1})
2✔
952
    $(_generate_unsafe_getindex!_body(1))
50,648✔
953
end
954

955
@eval function _unsafe_getindex!(dest::AbstractArray, src::AbstractArray, I::Vararg{Union{Real, AbstractArray},2})
956
    $(_generate_unsafe_getindex!_body(2))
28,434✔
957
end
958

959
@noinline throw_checksize_error(A, sz) = throw(DimensionMismatch("output array is the wrong size; expected $sz, got $(size(A))"))
×
960

961
## setindex! ##
962
function _setindex!(l::IndexStyle, A::AbstractArray, x, I::Union{Real, AbstractArray}...)
1,200✔
963
    @inline
35,550✔
964
    @boundscheck checkbounds(A, I...)
35,550✔
965
    _unsafe_setindex!(l, _maybe_reshape(l, A, I...), x, I...)
247,314✔
966
    A
35,543✔
967
end
968

969
function _generate_unsafe_setindex!_body(N::Int)
140✔
970
    quote
140✔
971
        x′ = unalias(A, x)
972
        @nexprs $N d->(I_d = unalias(A, I[d]))
973
        idxlens = @ncall $N index_lengths I
974
        @ncall $N setindex_shape_check x′ (d->idxlens[d])
975
        X = eachindex(x′)
976
        Xy = _prechecked_iterate(X)
977
        @inbounds @nloops $N i d->I_d begin
978
            (idx, state) = Xy::NTuple{2,Any}
979
            @ncall $N setindex! A x′[idx] i
980
            Xy = _prechecked_iterate(X, state)
981
        end
982
        A
983
    end
984
end
985

986
@generated function _unsafe_setindex!(::IndexStyle, A::AbstractArray, x, I::Vararg{Union{Real,AbstractArray}, N}) where N
583✔
987
    _generate_unsafe_setindex!_body(N)
141✔
988
end
989

990
@eval function _unsafe_setindex!(::IndexStyle, A::AbstractArray, x, I::Vararg{Union{Real,AbstractArray},1})
1,008✔
991
    $(_generate_unsafe_setindex!_body(1))
1,021✔
992
end
993

994
@eval function _unsafe_setindex!(::IndexStyle, A::AbstractArray, x, I::Vararg{Union{Real,AbstractArray},2})
5,181✔
995
    $(_generate_unsafe_setindex!_body(2))
33,952✔
996
end
997

998
diff(a::AbstractVector) = diff(a, dims=1)
20✔
999

1000
"""
1001
    diff(A::AbstractVector)
1002
    diff(A::AbstractArray; dims::Integer)
1003

1004
Finite difference operator on a vector or a multidimensional array `A`. In the
1005
latter case the dimension to operate on needs to be specified with the `dims`
1006
keyword argument.
1007

1008
!!! compat "Julia 1.1"
1009
    `diff` for arrays with dimension higher than 2 requires at least Julia 1.1.
1010

1011
# Examples
1012
```jldoctest
1013
julia> a = [2 4; 6 16]
1014
2×2 Matrix{Int64}:
1015
 2   4
1016
 6  16
1017

1018
julia> diff(a, dims=2)
1019
2×1 Matrix{Int64}:
1020
  2
1021
 10
1022

1023
julia> diff(vec(a))
1024
3-element Vector{Int64}:
1025
  4
1026
 -2
1027
 12
1028
```
1029
"""
1030
function diff(a::AbstractArray{T,N}; dims::Integer) where {T,N}
89✔
1031
    require_one_based_indexing(a)
44✔
1032
    1 <= dims <= N || throw(ArgumentError("dimension $dims out of range (1:$N)"))
46✔
1033

1034
    r = axes(a)
42✔
1035
    r0 = ntuple(i -> i == dims ? UnitRange(1, last(r[i]) - 1) : UnitRange(r[i]), N)
130✔
1036
    r1 = ntuple(i -> i == dims ? UnitRange(2, last(r[i])) : UnitRange(r[i]), N)
130✔
1037

1038
    return view(a, r1...) .- view(a, r0...)
42✔
1039
end
1040
function diff(r::AbstractRange{T}; dims::Integer=1) where {T}
19✔
1041
    dims == 1 || throw(ArgumentError("dimension $dims out of range (1:1)"))
19✔
1042
    return [@inbounds r[i+1] - r[i] for i in firstindex(r):lastindex(r)-1]
11✔
1043
end
1044

1045
### from abstractarray.jl
1046

1047
# In the common case where we have two views into the same parent, aliasing checks
1048
# are _much_ easier and more important to get right
1049
function mightalias(A::SubArray{T,<:Any,P}, B::SubArray{T,<:Any,P}) where {T,P}
310✔
1050
    if !_parentsmatch(A.parent, B.parent)
1,882✔
1051
        # We cannot do any better than the usual dataids check
1052
        return !_isdisjoint(dataids(A), dataids(B))
778✔
1053
    end
1054
    # Now we know that A.parent === B.parent. This means that the indices of A
1055
    # and B are the same length and indexing into the same dimensions. We can
1056
    # just walk through them and check for overlaps: O(ndims(A)). We must finally
1057
    # ensure that the indices don't alias with either parent
1058
    return _indicesmightoverlap(A.indices, B.indices) ||
552✔
1059
        !_isdisjoint(dataids(A.parent), _splatmap(dataids, B.indices)) ||
1060
        !_isdisjoint(dataids(B.parent), _splatmap(dataids, A.indices))
1061
end
1062
_parentsmatch(A::AbstractArray, B::AbstractArray) = A === B
34✔
1063
# Two reshape(::Array)s of the same size aren't `===` because they have different headers
1064
_parentsmatch(A::Array, B::Array) = pointer(A) == pointer(B) && size(A) == size(B)
1,848✔
1065

1066
_indicesmightoverlap(A::Tuple{}, B::Tuple{}) = true
×
1067
_indicesmightoverlap(A::Tuple{}, B::Tuple) = error("malformed subarray")
×
1068
_indicesmightoverlap(A::Tuple, B::Tuple{}) = error("malformed subarray")
×
1069
# For ranges, it's relatively cheap to construct the intersection
1070
@inline function _indicesmightoverlap(A::Tuple{AbstractRange, Vararg{Any}}, B::Tuple{AbstractRange, Vararg{Any}})
1071
    !isempty(intersect(A[1], B[1])) ? _indicesmightoverlap(tail(A), tail(B)) : false
×
1072
end
1073
# But in the common AbstractUnitRange case, there's an even faster shortcut
1074
@inline function _indicesmightoverlap(A::Tuple{AbstractUnitRange, Vararg{Any}}, B::Tuple{AbstractUnitRange, Vararg{Any}})
1075
    max(first(A[1]),first(B[1])) <= min(last(A[1]),last(B[1])) ? _indicesmightoverlap(tail(A), tail(B)) : false
554✔
1076
end
1077
# And we can check scalars against each other and scalars against arrays quite easily
1078
@inline _indicesmightoverlap(A::Tuple{Real, Vararg{Any}}, B::Tuple{Real, Vararg{Any}}) =
538✔
1079
    A[1] == B[1] ? _indicesmightoverlap(tail(A), tail(B)) : false
1080
@inline _indicesmightoverlap(A::Tuple{Real, Vararg{Any}}, B::Tuple{AbstractArray, Vararg{Any}}) =
1✔
1081
    A[1] in B[1] ? _indicesmightoverlap(tail(A), tail(B)) : false
1082
@inline _indicesmightoverlap(A::Tuple{AbstractArray, Vararg{Any}}, B::Tuple{Real, Vararg{Any}}) =
1✔
1083
    B[1] in A[1] ? _indicesmightoverlap(tail(A), tail(B)) : false
1084
# And small arrays are quick, too
1085
@inline function _indicesmightoverlap(A::Tuple{AbstractArray, Vararg{Any}}, B::Tuple{AbstractArray, Vararg{Any}})
1086
    if length(A[1]) == 1
×
1087
        return A[1][1] in B[1] ? _indicesmightoverlap(tail(A), tail(B)) : false
×
1088
    elseif length(B[1]) == 1
×
1089
        return B[1][1] in A[1] ? _indicesmightoverlap(tail(A), tail(B)) : false
×
1090
    else
1091
        # But checking larger arrays requires O(m*n) and is too much work
1092
        return true
×
1093
    end
1094
end
1095
# And in general, checking the intersection is too much work
1096
_indicesmightoverlap(A::Tuple{Any, Vararg{Any}}, B::Tuple{Any, Vararg{Any}}) = true
×
1097

1098
"""
1099
    fill!(A, x)
1100

1101
Fill array `A` with the value `x`. If `x` is an object reference, all elements will refer to
1102
the same object. `fill!(A, Foo())` will return `A` filled with the result of evaluating
1103
`Foo()` once.
1104

1105
# Examples
1106
```jldoctest
1107
julia> A = zeros(2,3)
1108
2×3 Matrix{Float64}:
1109
 0.0  0.0  0.0
1110
 0.0  0.0  0.0
1111

1112
julia> fill!(A, 2.)
1113
2×3 Matrix{Float64}:
1114
 2.0  2.0  2.0
1115
 2.0  2.0  2.0
1116

1117
julia> a = [1, 1, 1]; A = fill!(Vector{Vector{Int}}(undef, 3), a); a[1] = 2; A
1118
3-element Vector{Vector{Int64}}:
1119
 [2, 1, 1]
1120
 [2, 1, 1]
1121
 [2, 1, 1]
1122

1123
julia> x = 0; f() = (global x += 1; x); fill!(Vector{Int}(undef, 3), f())
1124
3-element Vector{Int64}:
1125
 1
1126
 1
1127
 1
1128
```
1129
"""
1130
function fill!(A::AbstractArray{T}, x) where T
135✔
1131
    xT = convert(T, x)
173,586✔
1132
    for I in eachindex(A)
18,309,337✔
1133
        @inbounds A[I] = xT
417,310,354✔
1134
    end
834,356,438✔
1135
    A
173,577✔
1136
end
1137

1138
function copyto!(dest::AbstractArray{T1,N}, Rdest::CartesianIndices{N},
579✔
1139
                  src::AbstractArray{T2,N}, Rsrc::CartesianIndices{N}) where {T1,T2,N}
1140
    isempty(Rdest) && return dest
1141
    if size(Rdest) != size(Rsrc)
1142
        throw(ArgumentError("source and destination must have same size (got $(size(Rsrc)) and $(size(Rdest)))"))
1143
    end
1144
    checkbounds(dest, first(Rdest))
1145
    checkbounds(dest, last(Rdest))
1146
    checkbounds(src, first(Rsrc))
1147
    checkbounds(src, last(Rsrc))
1148
    src′ = unalias(dest, src)
1149
    CRdest = CartesianIndices(Rdest)
1150
    CRsrc = CartesianIndices(Rsrc)
1151
    ΔI = first(CRdest) - first(CRsrc)
1152
    if @generated
1153
        quote
1154
            @nloops $N i (n->CRsrc.indices[n]) begin
1155
                @inbounds @nref($N,dest,n->Rdest.indices[n][i_n+ΔI[n]]) = @nref($N,src′,n->Rsrc.indices[n][i_n])
1156
            end
1157
        end
1158
    else
1159
        for I in CRsrc
1160
            @inbounds dest[Rdest[I + ΔI]] = src′[Rsrc[I]]
1161
        end
1162
    end
1163
    dest
1164
end
1165

1166
"""
1167
    copyto!(dest, Rdest::CartesianIndices, src, Rsrc::CartesianIndices) -> dest
1168

1169
Copy the block of `src` in the range of `Rsrc` to the block of `dest`
1170
in the range of `Rdest`. The sizes of the two regions must match.
1171

1172
# Examples
1173
```jldoctest
1174
julia> A = zeros(5, 5);
1175

1176
julia> B = [1 2; 3 4];
1177

1178
julia> Ainds = CartesianIndices((2:3, 2:3));
1179

1180
julia> Binds = CartesianIndices(B);
1181

1182
julia> copyto!(A, Ainds, B, Binds)
1183
5×5 Matrix{Float64}:
1184
 0.0  0.0  0.0  0.0  0.0
1185
 0.0  1.0  2.0  0.0  0.0
1186
 0.0  3.0  4.0  0.0  0.0
1187
 0.0  0.0  0.0  0.0  0.0
1188
 0.0  0.0  0.0  0.0  0.0
1189
```
79,082✔
1190
"""
79,082✔
1191
copyto!(::AbstractArray, ::CartesianIndices, ::AbstractArray, ::CartesianIndices)
79,082✔
1192

3,173,283✔
1193
# circshift!
1194
circshift!(dest::AbstractArray, src, ::Tuple{}) = copyto!(dest, src)
×
1195
"""
1196
    circshift!(dest, src, shifts)
1197

200,416✔
1198
Circularly shift, i.e. rotate, the data in `src`, storing the result in
1199
`dest`. `shifts` specifies the amount to shift in each dimension.
1200

1201
$(_DOCS_ALIASING_WARNING)
1202

1203
See also [`circshift`](@ref).
1204
"""
1205
@noinline function circshift!(dest::AbstractArray{T,N}, src, shiftamt::DimsInteger) where {T,N}
182✔
1206
    dest === src && throw(ArgumentError("dest and src must be separate arrays"))
182✔
1207
    inds = axes(src)
181✔
1208
    axes(dest) == inds || throw(ArgumentError("indices of src and dest must match (got $inds and $(axes(dest)))"))
181✔
1209
    isempty(src) && return dest
181✔
1210
    _circshift!(dest, (), src, (), inds, fill_to_length(shiftamt, 0, Val(N)))
179✔
1211
end
1212

1213
circshift!(dest::AbstractArray, src, shiftamt) =
9✔
1214
    circshift!(dest, src, map(Integer, (shiftamt...,)))
1215

1216
# For each dimension, we copy the first half of src to the second half
1217
# of dest, and the second half of src to the first half of dest. This
1218
# uses a recursive bifurcation strategy so that these splits can be
1219
# encoded by ranges, which means that we need only one call to `mod`
1220
# per dimension rather than one call per index.
1221
# `rdest` and `rsrc` are tuples-of-ranges that grow one dimension at a
1222
# time; when all the dimensions have been filled in, you call `copyto!`
1223
# for that block. In other words, in two dimensions schematically we
1224
# have the following call sequence (--> means a call):
1225
#   circshift!(dest, src, shiftamt) -->
1226
#     _circshift!(dest, src, ("first half of dim1",)) -->
1227
#       _circshift!(dest, src, ("first half of dim1", "first half of dim2")) --> copyto!
34,973✔
1228
#       _circshift!(dest, src, ("first half of dim1", "second half of dim2")) --> copyto!
34,973✔
1229
#     _circshift!(dest, src, ("second half of dim1",)) -->
34,973✔
1230
#       _circshift!(dest, src, ("second half of dim1", "first half of dim2")) --> copyto!
38,404✔
1231
#       _circshift!(dest, src, ("second half of dim1", "second half of dim2")) --> copyto!
34,967✔
1232
@inline function _circshift!(dest, rdest, src, rsrc,
34,971✔
1233
                             inds::Tuple{AbstractUnitRange,Vararg{Any}},
314,277✔
1234
                             shiftamt::Tuple{Integer,Vararg{Any}})::typeof(dest)
1235
    ind1, d = inds[1], shiftamt[1]
267✔
1236
    s = mod(d, length(ind1))
534✔
1237
    sf, sl = first(ind1)+s, last(ind1)-s
267✔
1238
    r1, r2 = first(ind1):sf-1, sf:last(ind1)
35,234✔
1239
    r3, r4 = first(ind1):sl, sl+1:last(ind1)
299✔
1240
    tinds, tshiftamt = tail(inds), tail(shiftamt)
267✔
1241
    _circshift!(dest, (rdest..., r1), src, (rsrc..., r4), tinds, tshiftamt)
275✔
1242
    _circshift!(dest, (rdest..., r2), src, (rsrc..., r3), tinds, tshiftamt)
267✔
1243
end
1244
# At least one of inds, shiftamt is empty
1245
function _circshift!(dest, rdest, src, rsrc, inds, shiftamt)
1246
    copyto!(dest, CartesianIndices(rdest), src, CartesianIndices(rsrc))
446✔
1247
end
1248

1249
# circcopy!
1250
"""
1251
    circcopy!(dest, src)
1252

1253
Copy `src` to `dest`, indexing each dimension modulo its length.
1254
`src` and `dest` must have the same size, but can be offset in
1255
their indices; any offset results in a (circular) wraparound. If the
1256
arrays have overlapping indices, then on the domain of the overlap
1257
`dest` agrees with `src`.
1258

1259
$(_DOCS_ALIASING_WARNING)
1260

1261
See also: [`circshift`](@ref).
1262

1263
# Examples
1264
```julia-repl
1265
julia> src = reshape(Vector(1:16), (4,4))
1266
4×4 Array{Int64,2}:
1267
 1  5   9  13
1268
 2  6  10  14
1269
 3  7  11  15
1270
 4  8  12  16
1271

1272
julia> dest = OffsetArray{Int}(undef, (0:3,2:5))
1273

1274
julia> circcopy!(dest, src)
1275
OffsetArrays.OffsetArray{Int64,2,Array{Int64,2}} with indices 0:3×2:5:
1276
 8  12  16  4
1277
 5   9  13  1
1278
 6  10  14  2
1279
 7  11  15  3
1280

1281
julia> dest[1:3,2:4] == src[1:3,2:4]
1282
true
1283
```
1284
"""
1285
function circcopy!(dest, src)
2✔
1286
    dest === src && throw(ArgumentError("dest and src must be separate arrays"))
2✔
1287
    indssrc, indsdest = axes(src), axes(dest)
2✔
1288
    if (szsrc = map(length, indssrc)) != (szdest = map(length, indsdest))
4✔
1289
        throw(DimensionMismatch("src and dest must have the same sizes (got $szsrc and $szdest)"))
×
1290
    end
1291
    shift = map((isrc, idest)->first(isrc)-first(idest), indssrc, indsdest)
6✔
1292
    all(x->x==0, shift) && return copyto!(dest, src)
7✔
1293
    _circcopy!(dest, (), indsdest, src, (), indssrc)
1✔
1294
end
1295

1296
# This uses the same strategy described above for _circshift!
1297
@inline function _circcopy!(dest, rdest, indsdest::Tuple{AbstractUnitRange,Vararg{Any}},
1298
                            src,  rsrc,  indssrc::Tuple{AbstractUnitRange,Vararg{Any}})::typeof(dest)
1299
    indd1, inds1 = indsdest[1], indssrc[1]
3✔
1300
    l = length(indd1)
3✔
1301
    s = mod(first(inds1)-first(indd1), l)
6✔
1302
    sdf = first(indd1)+s
3✔
1303
    rd1, rd2 = first(indd1):sdf-1, sdf:last(indd1)
3✔
1304
    ssf = last(inds1)-s
3✔
1305
    rs1, rs2 = first(inds1):ssf, ssf+1:last(inds1)
3✔
1306
    tindsd, tindss = tail(indsdest), tail(indssrc)
3✔
1307
    _circcopy!(dest, (rdest..., rd1), tindsd, src, (rsrc..., rs2), tindss)
3✔
1308
    _circcopy!(dest, (rdest..., rd2), tindsd, src, (rsrc..., rs1), tindss)
3✔
1309
end
1310

1311
# At least one of indsdest, indssrc are empty (and both should be, since we've checked)
1312
function _circcopy!(dest, rdest, indsdest, src, rsrc, indssrc)
1313
    copyto!(dest, CartesianIndices(rdest), src, CartesianIndices(rsrc))
4✔
1314
end
1315

1316
### BitArrays
1317

1318
## getindex
1319

1320
# contiguous multidimensional indexing: if the first dimension is a range,
1321
# we can get some performance from using copy_chunks!
1322
@inline function _unsafe_getindex!(X::BitArray, B::BitArray, I0::Union{AbstractUnitRange{Int},Slice})
×
1323
    copy_chunks!(X.chunks, 1, B.chunks, indexoffset(I0)+1, length(I0))
×
1324
    return X
×
1325
end
1326

1327
# Optimization where the inner dimension is contiguous improves perf dramatically
1328
@generated function _unsafe_getindex!(X::BitArray, B::BitArray,
91,869✔
1329
        I0::Union{Slice,UnitRange{Int}}, I::Union{Int,AbstractUnitRange{Int},Slice}...)
1330
    N = length(I)
28✔
1331
    quote
28✔
1332
        $(Expr(:meta, :inline))
1333
        @nexprs $N d->(I_d = I[d])
1334

1335
        idxlens = @ncall $N index_lengths I0 I
1336

1337
        f0 = indexoffset(I0)+1
1338
        l0 = idxlens[1]
1339

1340
        gap_lst_1 = 0
1341
        @nexprs $N d->(gap_lst_{d+1} = idxlens[d+1])
1342
        stride = 1
1343
        ind = f0
1344
        @nexprs $N d->begin
1345
            stride *= size(B, d)
1346
            stride_lst_d = stride
1347
            ind += stride * indexoffset(I_d)
1348
            gap_lst_{d+1} *= stride
1349
        end
1350

1351
        storeind = 1
1352
        Xc, Bc = X.chunks, B.chunks
1353
        @nloops($N, i, d->(1:idxlens[d+1]),
1354
                d->nothing, # PRE
1355
                d->(ind += stride_lst_d - gap_lst_d), # POST
1356
                begin # BODY
1357
                    copy_chunks!(Xc, storeind, Bc, ind, l0)
1358
                    storeind += l0
1359
                end)
1360
        return X
1361
    end
1362
end
1363

1364
# in the general multidimensional non-scalar case, can we do about 10% better
1365
# in most cases by manually hoisting the bitarray chunks access out of the loop
1366
# (This should really be handled by the compiler or with an immutable BitArray)
1367
@generated function _unsafe_getindex!(X::BitArray, B::BitArray, I::Union{Int,AbstractArray{Int}}...)
15,980✔
1368
    N = length(I)
52✔
1369
    quote
52✔
1370
        $(Expr(:meta, :inline))
1371
        stride_1 = 1
1372
        @nexprs $N d->(stride_{d+1} = stride_d*size(B, d))
1373
        $(Symbol(:offset_, N)) = 1
1374
        ind = 0
1375
        Xc, Bc = X.chunks, B.chunks
1376
        @nloops $N i d->I[d] d->(@inbounds offset_{d-1} = offset_d + (i_d-1)*stride_d) begin
1377
            ind += 1
1378
            unsafe_bitsetindex!(Xc, unsafe_bitgetindex(Bc, offset_0), ind)
1379
        end
1380
        return X
1381
    end
1382
end
1383

1384
## setindex!
1385

1386
function copy_to_bitarray_chunks!(Bc::Vector{UInt64}, pos_d::Int, C::StridedArray, pos_s::Int, numbits::Int)
45✔
1387
    bind = pos_d
45✔
1388
    cind = pos_s
45✔
1389
    lastind = pos_d + numbits - 1
45✔
1390
    @inbounds while bind ≤ lastind
45✔
1391
        unsafe_bitsetindex!(Bc, Bool(C[cind]), bind)
4,930✔
1392
        bind += 1
4,930✔
1393
        cind += 1
4,930✔
1394
    end
4,930✔
1395
end
1396

1397
# Note: the next two functions rely on the following definition of the conversion to Bool:
1398
#   convert(::Type{Bool}, x::Real) = x==0 ? false : x==1 ? true : throw(InexactError(...))
1399
# they're used to preemptively check in bulk when possible, which is much faster.
1400
# Also, the functions can be overloaded for custom types T<:Real :
1401
#  a) in the unlikely eventuality that they use a different logic for Bool conversion
1402
#  b) to skip the check if not necessary
1403
@inline try_bool_conversion(x::Real) =
8,272,844✔
1404
    x == 0 || x == 1 || throw(InexactError(:try_bool_conversion, Bool, x))
1405
@inline unchecked_bool_convert(x::Real) = x == 1
4,746,288✔
1406

1407
function copy_to_bitarray_chunks!(Bc::Vector{UInt64}, pos_d::Int, C::StridedArray{<:Real}, pos_s::Int, numbits::Int)
23,816✔
1408
    @inbounds for i = (1:numbits) .+ (pos_s - 1)
482,236✔
1409
        try_bool_conversion(C[i])
8,296,660✔
1410
    end
9,468,760✔
1411

1412
    kd0, ld0 = get_chunks_id(pos_d)
23,816✔
1413
    kd1, ld1 = get_chunks_id(pos_d + numbits - 1)
23,816✔
1414

1415
    delta_kd = kd1 - kd0
23,816✔
1416

1417
    u = _msk64
23,816✔
1418
    if delta_kd == 0
23,816✔
1419
        msk_d0 = msk_d1 = ~(u << ld0) | (u << (ld1+1))
11,656✔
1420
        lt0 = ld1
11,656✔
1421
    else
1422
        msk_d0 = ~(u << ld0)
12,160✔
1423
        msk_d1 = (u << (ld1+1))
12,160✔
1424
        lt0 = 63
12,160✔
1425
    end
1426

1427
    bind = kd0
23,816✔
1428
    ind = pos_s
23,816✔
1429
    @inbounds if ld0 > 0
23,816✔
1430
        c = UInt64(0)
20,908✔
1431
        for j = ld0:lt0
20,908✔
1432
            c |= (UInt64(unchecked_bool_convert(C[ind])) << j)
128,636✔
1433
            ind += 1
128,636✔
1434
        end
236,364✔
1435
        Bc[kd0] = (Bc[kd0] & msk_d0) | (c & ~msk_d0)
20,908✔
1436
        bind += 1
20,908✔
1437
    end
1438

1439
    nc = _div64(numbits - ind + pos_s)
23,816✔
1440
    @inbounds for i = 1:nc
23,816✔
1441
        c = UInt64(0)
64,988✔
1442
        for j = 0:63
64,988✔
1443
            c |= (UInt64(unchecked_bool_convert(C[ind])) << j)
4,159,232✔
1444
            ind += 1
4,159,232✔
1445
        end
8,253,476✔
1446
        Bc[bind] = c
64,988✔
1447
        bind += 1
64,988✔
1448
    end
120,908✔
1449

1450
    @inbounds if bind ≤ kd1
23,816✔
1451
        @assert bind == kd1
13,196✔
1452
        c = UInt64(0)
13,196✔
1453
        for j = 0:ld1
13,196✔
1454
            c |= (UInt64(unchecked_bool_convert(C[ind])) << j)
458,420✔
1455
            ind += 1
×
1456
        end
×
1457
        Bc[kd1] = (Bc[kd1] & msk_d1) | (c & ~msk_d1)
×
1458
    end
1459
end
1460

1461
# contiguous multidimensional indexing: if the first dimension is a range,
1462
# we can get some performance from using copy_chunks!
1463

1464
@inline function setindex!(B::BitArray, X::Union{StridedArray,BitArray}, J0::Union{Colon,AbstractUnitRange{Int}})
126✔
1465
    I0 = to_indices(B, (J0,))[1]
126✔
1466
    @boundscheck checkbounds(B, I0)
126✔
1467
    l0 = length(I0)
126✔
1468
    setindex_shape_check(X, l0)
126✔
1469
    l0 == 0 && return B
126✔
1470
    f0 = indexoffset(I0)+1
126✔
1471
    copy_to_bitarray_chunks!(B.chunks, f0, X, 1, l0)
126✔
1472
    return B
126✔
1473
end
1474

1475
@inline function setindex!(B::BitArray, X::Union{StridedArray,BitArray},
12✔
1476
        I0::Union{Colon,AbstractUnitRange{Int}}, I::Union{Int,AbstractUnitRange{Int},Colon}...)
1477
    J = to_indices(B, (I0, I...))
1,261✔
1478
    @boundscheck checkbounds(B, J...)
1,261✔
1479
    _unsafe_setindex!(B, X, J...)
2,502✔
1480
end
1481
@generated function _unsafe_setindex!(B::BitArray, X::Union{StridedArray,BitArray},
2,506✔
1482
        I0::Union{Slice,AbstractUnitRange{Int}}, I::Union{Int,AbstractUnitRange{Int},Slice}...)
1483
    N = length(I)
20✔
1484
    quote
20✔
1485
        idxlens = @ncall $N index_lengths I0 d->I[d]
1486
        @ncall $N setindex_shape_check X idxlens[1] d->idxlens[d+1]
1487
        isempty(X) && return B
1488
        f0 = indexoffset(I0)+1
1489
        l0 = idxlens[1]
1490

1491
        gap_lst_1 = 0
1492
        @nexprs $N d->(gap_lst_{d+1} = idxlens[d+1])
1493
        stride = 1
1494
        ind = f0
1495
        @nexprs $N d->begin
1496
            stride *= size(B, d)
1497
            stride_lst_d = stride
1498
            ind += stride * indexoffset(I[d])
1499
            gap_lst_{d+1} *= stride
1500
        end
1501

1502
        refind = 1
1503
        Bc = B.chunks
1504
        @nloops($N, i, d->I[d],
1505
                d->nothing, # PRE
1506
                d->(ind += stride_lst_d - gap_lst_d), # POST
1507
                begin # BODY
1508
                    copy_to_bitarray_chunks!(Bc, ind, X, refind, l0)
1509
                    refind += l0
1510
                end)
1511

1512
        return B
1513
    end
1514
end
1515

1516
@propagate_inbounds function setindex!(B::BitArray, X::AbstractArray,
2✔
1517
        I0::Union{Colon,AbstractUnitRange{Int}}, I::Union{Int,AbstractUnitRange{Int},Colon}...)
1518
    _setindex!(IndexStyle(B), B, X, to_indices(B, (I0, I...))...)
2✔
1519
end
1520

1521
## fill! contiguous views of BitArrays with a single value
1522
function fill!(V::SubArray{Bool, <:Any, <:BitArray, <:Tuple{AbstractUnitRange{Int}}}, x)
1523
    B = V.parent
257✔
1524
    I0 = V.indices[1]
257✔
1525
    l0 = length(I0)
329✔
1526
    l0 == 0 && return V
329✔
1527
    fill_chunks!(B.chunks, Bool(x), first(I0), l0)
384✔
1528
    return V
329✔
1529
end
1530

1531
fill!(V::SubArray{Bool, <:Any, <:BitArray, <:Tuple{AbstractUnitRange{Int}, Vararg{Union{Int,AbstractUnitRange{Int}}}}}, x) =
19✔
1532
    _unsafe_fill_indices!(V.parent, x, V.indices...)
1533

1534
@generated function _unsafe_fill_indices!(B::BitArray, x,
19✔
1535
        I0::AbstractUnitRange{Int}, I::Union{Int,AbstractUnitRange{Int}}...)
1536
    N = length(I)
12✔
1537
    quote
12✔
1538
        y = Bool(x)
1539
        idxlens = @ncall $N index_lengths I0 d->I[d]
1540

1541
        f0 = indexoffset(I0)+1
1542
        l0 = idxlens[1]
1543
        l0 == 0 && return B
1544
        @nexprs $N d->(isempty(I[d]) && return B)
1545

1546
        gap_lst_1 = 0
1547
        @nexprs $N d->(gap_lst_{d+1} = idxlens[d+1])
1548
        stride = 1
1549
        ind = f0
1550
        @nexprs $N d->begin
1551
            stride *= size(B, d)
1552
            stride_lst_d = stride
1553
            ind += stride * indexoffset(I[d])
1554
            gap_lst_{d+1} *= stride
1555
        end
1556

1557
        @nloops($N, i, d->I[d],
1558
                d->nothing, # PRE
1559
                d->(ind += stride_lst_d - gap_lst_d), # POST
1560
                fill_chunks!(B.chunks, y, ind, l0) # BODY
1561
                )
1562

1563
        return B
1564
    end
1565
end
1566

1567
## isassigned
1568

1569
@generated function isassigned(B::BitArray, I_0::Int, I::Int...)
×
1570
    N = length(I)
×
1571
    quote
×
1572
        @nexprs $N d->(I_d = I[d])
×
1573
        stride = 1
×
1574
        index = I_0
×
1575
        @nexprs $N d->begin
×
1576
            l = size(B,d)
×
1577
            stride *= l
×
1578
            @boundscheck 1 <= I_{d-1} <= l || return false
×
1579
            index += (I_d - 1) * stride
×
1580
        end
1581
        return isassigned(B, index)
×
1582
    end
1583
end
1584

1585
@propagate_inbounds isassigned(A::AbstractArray, i::CartesianIndex) = isassigned(A, Tuple(i)...)
3,449,836✔
1586
@propagate_inbounds function isassigned(A::AbstractArray, i::Union{Integer, CartesianIndex}...)
13✔
1587
    return isassigned(A, CartesianIndex(to_indices(A, i)))
544✔
1588
end
1589
@inline function isassigned(A::AbstractArray, i::Integer...)
2,143✔
1590
    # convert to valid indices, checking for Bool
1591
    inds = to_indices(A, i)
44,649,164✔
1592
    @boundscheck checkbounds(Bool, A, inds...) || return false
45,895,722✔
1593
    S = IndexStyle(A)
2,554,472✔
1594
    ninds = length(inds)
2,554,472✔
1595
    if (isa(S, IndexLinear) && ninds != 1)
2,554,472✔
1596
        return @inbounds isassigned(A, _to_linear_index(A, inds...))
529,502✔
1597
    elseif (!isa(S, IndexLinear) && ninds != ndims(A))
2,024,970✔
1598
        return @inbounds isassigned(A, _to_subscript_indices(A, inds...)...)
38✔
1599
    else
1600
       try
45,366,149✔
1601
            A[inds...]
45,370,449✔
1602
            true
45,366,149✔
1603
        catch e
1604
            if isa(e, BoundsError) || isa(e, UndefRefError)
62✔
1605
                return false
30✔
1606
            else
1607
                rethrow()
1✔
1608
            end
1609
        end
1610
    end
1611
end
1612

1613
# _unsetindex
1614
@propagate_inbounds function Base._unsetindex!(A::AbstractArray, i::CartesianIndex)
1615
    Base._unsetindex!(A, to_indices(A, (i,))...)
16✔
1616
    return A
12✔
1617
end
1618

1619
## permutedims
1620

1621
## Permute array dims ##
1622

1623
function permutedims(B::StridedArray, perm)
198✔
1624
    dimsB = size(B)
211✔
1625
    ndimsB = length(dimsB)
211✔
1626
    (ndimsB == length(perm) && isperm(perm)) || throw(ArgumentError("no valid permutation of dimensions"))
211✔
1627
    dimsP = ntuple(i->dimsB[perm[i]], ndimsB)::typeof(dimsB)
421✔
1628
    P = similar(B, dimsP)
421✔
1629
    permutedims!(P, B, perm)
211✔
1630
end
1631

1632
function checkdims_perm(P::AbstractArray{TP,N}, B::AbstractArray{TB,N}, perm) where {TP,TB,N}
136✔
1633
    indsB = axes(B)
289✔
1634
    length(perm) == N || throw(ArgumentError("expected permutation of size $N, but length(perm)=$(length(perm))"))
289✔
1635
    isperm(perm) || throw(ArgumentError("input is not a permutation"))
294✔
1636
    indsP = axes(P)
284✔
1637
    for i = 1:length(perm)
284✔
1638
        indsP[i] == indsB[perm[i]] || throw(DimensionMismatch("destination tensor of incorrect size"))
799✔
1639
    end
1,025✔
1640
    nothing
1641
end
1642

1643
for (V, PT, BT) in Any[((:N,), BitArray, BitArray), ((:T,:N), Array, StridedArray)]
1644
    @eval @generated function permutedims!(P::$PT{$(V...)}, B::$BT{$(V...)}, perm) where $(V...)
218✔
1645
        quote
40✔
1646
            checkdims_perm(P, B, perm)
1647

1648
            #calculates all the strides
1649
            native_strides = size_to_strides(1, size(B)...)
1650
            strides = @ntuple $N d->native_strides[perm[d]]
1651
            strides::NTuple{$N,Integer}
1652

1653
            #Creates offset, because indexing starts at 1
1654
            offset = 1 - reduce(+, strides, init = 0)
1655

1656
            sumc = 0
1657
            ind = 1
1658
            @nloops($N, i, P,
1659
                    d->(sumc += i_d*strides[d]), # PRE
1660
                    d->(sumc -= i_d*strides[d]), # POST
1661
                    begin # BODY
1662
                        @inbounds P[ind] = B[sumc+offset]
1663
                        ind += 1
1664
                    end)
1665

1666
            return P
1667
        end
1668
    end
1669
end
1670

1671
## unique across dim
1672

1673
# TODO: this doesn't fit into the new hashing scheme in any obvious way
1674

1675
struct Prehashed
1676
    hash::UInt
893✔
1677
end
1678
hash(x::Prehashed) = x.hash
893✔
1679

1680
"""
1681
    unique(A::AbstractArray; dims::Int)
1682

1683
Return unique regions of `A` along dimension `dims`.
1684

1685
# Examples
1686
```jldoctest
1687
julia> A = map(isodd, reshape(Vector(1:8), (2,2,2)))
1688
2×2×2 Array{Bool, 3}:
1689
[:, :, 1] =
1690
 1  1
1691
 0  0
1692

1693
[:, :, 2] =
1694
 1  1
1695
 0  0
1696

1697
julia> unique(A)
1698
2-element Vector{Bool}:
1699
 1
1700
 0
1701

1702
julia> unique(A, dims=2)
1703
2×1×2 Array{Bool, 3}:
1704
[:, :, 1] =
1705
 1
1706
 0
1707

1708
[:, :, 2] =
1709
 1
1710
 0
1711

1712
julia> unique(A, dims=3)
1713
2×2×1 Array{Bool, 3}:
1714
[:, :, 1] =
1715
 1  1
1716
 0  0
1717
```
1718
"""
1719
unique(A::AbstractArray; dims::Union{Colon,Integer} = :) = _unique_dims(A, dims)
14,506✔
1720

1721
_unique_dims(A::AbstractArray, dims::Colon) = invoke(unique, Tuple{Any}, A)
7,242✔
1722

1723
@generated function _unique_dims(A::AbstractArray{T,N}, dim::Integer) where {T,N}
11✔
1724
    quote
5✔
1725
        1 <= dim <= $N || return copy(A)
1726
        hashes = zeros(UInt, axes(A, dim))
1727

1728
        # Compute hash for each row
1729
        k = 0
1730
        @nloops $N i A d->(if d == dim; k = i_d; end) begin
1731
            @inbounds hashes[k] = hash(hashes[k], hash((@nref $N A i)))
1732
        end
1733

1734
        # Collect index of first row for each hash
1735
        uniquerow = similar(Array{Int}, axes(A, dim))
1736
        firstrow = Dict{Prehashed,Int}()
1737
        for k = axes(A, dim)
1738
            uniquerow[k] = get!(firstrow, Prehashed(hashes[k]), k)
1739
        end
1740
        uniquerows = collect(values(firstrow))
1741

1742
        # Check for collisions
1743
        collided = falses(axes(A, dim))
1744
        @inbounds begin
1745
            @nloops $N i A d->(if d == dim
1746
                k = i_d
1747
                j_d = uniquerow[k]
1748
            else
1749
                j_d = i_d
1750
            end) begin
1751
                if !isequal((@nref $N A j), (@nref $N A i))
1752
                    collided[k] = true
1753
                end
1754
            end
1755
        end
1756

1757
        if any(collided)
1758
            nowcollided = similar(BitArray, axes(A, dim))
1759
            while any(collided)
1760
                # Collect index of first row for each collided hash
1761
                empty!(firstrow)
1762
                for j = axes(A, dim)
1763
                    collided[j] || continue
1764
                    uniquerow[j] = get!(firstrow, Prehashed(hashes[j]), j)
1765
                end
1766
                for v in values(firstrow)
1767
                    push!(uniquerows, v)
1768
                end
1769

1770
                # Check for collisions
1771
                fill!(nowcollided, false)
1772
                @nloops $N i A d->begin
1773
                    if d == dim
1774
                        k = i_d
1775
                        j_d = uniquerow[k]
1776
                        (!collided[k] || j_d == k) && continue
1777
                    else
1778
                        j_d = i_d
1779
                    end
1780
                end begin
1781
                    if !isequal((@nref $N A j), (@nref $N A i))
1782
                        nowcollided[k] = true
1783
                    end
1784
                end
1785
                (collided, nowcollided) = (nowcollided, collided)
1786
            end
1787
        end
1788

1789
        @nref $N A d->d == dim ? sort!(uniquerows) : (axes(A, d))
1790
    end
1791
end
1792

1793
# Show for pairs() with Cartesian indices. Needs to be here rather than show.jl for bootstrap order
1794
function Base.showarg(io::IO, r::Iterators.Pairs{<:Integer, <:Any, <:Any, T}, toplevel) where T <: Union{AbstractVector, Tuple}
1✔
1795
    print(io, "pairs(::$T)")
1✔
1796
end
1797
function Base.showarg(io::IO, r::Iterators.Pairs{<:CartesianIndex, <:Any, <:Any, T}, toplevel) where T <: AbstractArray
×
1798
    print(io, "pairs(::$T)")
×
1799
end
1800

1801
function Base.showarg(io::IO, r::Iterators.Pairs{<:CartesianIndex, <:Any, <:Any, T}, toplevel) where T<:AbstractVector
1✔
1802
    print(io, "pairs(IndexCartesian(), ::$T)")
1✔
1803
end
1804

1805
## sortslices
1806

1807
"""
1808
    sortslices(A; dims, alg::Algorithm=DEFAULT_UNSTABLE, lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward)
1809

1810
Sort slices of an array `A`. The required keyword argument `dims` must
1811
be either an integer or a tuple of integers. It specifies the
1812
dimension(s) over which the slices are sorted.
1813

1814
E.g., if `A` is a matrix, `dims=1` will sort rows, `dims=2` will sort columns.
1815
Note that the default comparison function on one dimensional slices sorts
1816
lexicographically.
1817

1818
For the remaining keyword arguments, see the documentation of [`sort!`](@ref).
1819

1820
# Examples
1821
```jldoctest
1822
julia> sortslices([7 3 5; -1 6 4; 9 -2 8], dims=1) # Sort rows
1823
3×3 Matrix{Int64}:
1824
 -1   6  4
1825
  7   3  5
1826
  9  -2  8
1827

1828
julia> sortslices([7 3 5; -1 6 4; 9 -2 8], dims=1, lt=(x,y)->isless(x[2],y[2]))
1829
3×3 Matrix{Int64}:
1830
  9  -2  8
1831
  7   3  5
1832
 -1   6  4
1833

1834
julia> sortslices([7 3 5; -1 6 4; 9 -2 8], dims=1, rev=true)
1835
3×3 Matrix{Int64}:
1836
  9  -2  8
1837
  7   3  5
1838
 -1   6  4
1839

1840
julia> sortslices([7 3 5; 6 -1 -4; 9 -2 8], dims=2) # Sort columns
1841
3×3 Matrix{Int64}:
1842
  3   5  7
1843
 -1  -4  6
1844
 -2   8  9
1845

1846
julia> sortslices([7 3 5; 6 -1 -4; 9 -2 8], dims=2, alg=InsertionSort, lt=(x,y)->isless(x[2],y[2]))
1847
3×3 Matrix{Int64}:
1848
  5   3  7
1849
 -4  -1  6
1850
  8  -2  9
1851

1852
julia> sortslices([7 3 5; 6 -1 -4; 9 -2 8], dims=2, rev=true)
1853
3×3 Matrix{Int64}:
1854
 7   5   3
1855
 6  -4  -1
1856
 9   8  -2
1857
```
1858

1859
# Higher dimensions
1860

1861
`sortslices` extends naturally to higher dimensions. E.g., if `A` is a
1862
a 2x2x2 array, `sortslices(A, dims=3)` will sort slices within the 3rd dimension,
1863
passing the 2x2 slices `A[:, :, 1]` and `A[:, :, 2]` to the comparison function.
1864
Note that while there is no default order on higher-dimensional slices, you may
1865
use the `by` or `lt` keyword argument to specify such an order.
1866

1867
If `dims` is a tuple, the order of the dimensions in `dims` is
1868
relevant and specifies the linear order of the slices. E.g., if `A` is three
1869
dimensional and `dims` is `(1, 2)`, the orderings of the first two dimensions
1870
are re-arranged such that the slices (of the remaining third dimension) are sorted.
1871
If `dims` is `(2, 1)` instead, the same slices will be taken,
1872
but the result order will be row-major instead.
1873

1874
# Higher dimensional examples
1875
```
1876
julia> A = [4 3; 2 1 ;;; 'A' 'B'; 'C' 'D']
1877
2×2×2 Array{Any, 3}:
1878
[:, :, 1] =
1879
 4  3
1880
 2  1
1881

1882
[:, :, 2] =
1883
 'A'  'B'
1884
 'C'  'D'
1885

1886
julia> sortslices(A, dims=(1,2))
1887
2×2×2 Array{Any, 3}:
1888
[:, :, 1] =
1889
 1  3
1890
 2  4
1891

1892
[:, :, 2] =
1893
 'D'  'B'
1894
 'C'  'A'
1895

1896
julia> sortslices(A, dims=(2,1))
1897
2×2×2 Array{Any, 3}:
1898
[:, :, 1] =
1899
 1  2
1900
 3  4
1901

1902
[:, :, 2] =
1903
 'D'  'C'
1904
 'B'  'A'
1905

1906
julia> sortslices(reshape([5; 4; 3; 2; 1], (1,1,5)), dims=3, by=x->x[1,1])
1907
1×1×5 Array{Int64, 3}:
1908
[:, :, 1] =
1909
 1
1910

1911
[:, :, 2] =
1912
 2
1913

1914
[:, :, 3] =
1915
 3
1916

1917
[:, :, 4] =
1918
 4
1919

1920
[:, :, 5] =
1921
 5
1922
```
1923
"""
1924
function sortslices(A::AbstractArray; dims::Union{Integer, Tuple{Vararg{Integer}}}, kws...)
36✔
1925
    if A isa Matrix && dims isa Integer && dims == 1
18✔
1926
        # TODO: remove once the generic version becomes as fast or faster
1927
        perm = sortperm(eachslice(A; dims); kws...)
6✔
1928
        return A[perm, :]
6✔
1929
    end
1930

1931
    B = similar(A)
24✔
1932
    _sortslices!(B, A, Val{dims}(); kws...)
12✔
1933
    B
12✔
1934
end
1935

1936
function _sortslices!(B, A, ::Val{dims}; kws...) where dims
24✔
1937
    ves = vec(eachslice(A; dims))
13✔
1938
    perm = sortperm(ves; kws...)
12✔
1939
    bes = eachslice(B; dims)
18✔
1940

1941
    # TODO for further optimization: traverse in memory order
1942
    for (slice, i) in zip(eachslice(B; dims), perm)
24✔
1943
        slice .= ves[i]
70✔
1944
    end
41✔
1945
end
1946

1947
getindex(b::Ref, ::CartesianIndex{0}) = getindex(b)
4✔
1948
setindex!(b::Ref, x, ::CartesianIndex{0}) = setindex!(b, x)
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc