@@ -149,13 +149,13 @@ module IteratorsMD
149149 function Base. nextind (a:: AbstractArray{<:Any,N} , i:: CartesianIndex{N} ) where {N}
150150 iter = CartesianIndices (axes (a))
151151 # might overflow
152- I = inc (i. I, first (iter). I, last (iter). I)
152+ I = inc (i. I, first (iter). I, step .(iter . indices), last (iter). I)
153153 return I
154154 end
155155 function Base. prevind (a:: AbstractArray{<:Any,N} , i:: CartesianIndex{N} ) where {N}
156156 iter = CartesianIndices (axes (a))
157157 # might underflow
158- I = dec (i. I, last (iter). I, first (iter). I)
158+ I = dec (i. I, last (iter). I, step .(iter . indices), first (iter). I)
159159 return I
160160 end
161161
@@ -169,15 +169,15 @@ module IteratorsMD
169169 # Iteration
170170 """
171171 CartesianIndices(sz::Dims) -> R
172- CartesianIndices((istart:istop, jstart:jstop, ...)) -> R
172+ CartesianIndices((istart:[istep:] istop, jstart:[jstep:] jstop, ...)) -> R
173173
174174 Define a region `R` spanning a multidimensional rectangular range
175175 of integer indices. These are most commonly encountered in the
176176 context of iteration, where `for I in R ... end` will return
177177 [`CartesianIndex`](@ref) indices `I` equivalent to the nested loops
178178
179- for j = jstart:jstop
180- for i = istart:istop
179+ for j = jstart:jstep: jstop
180+ for i = istart:istep: istop
181181 ...
182182 end
183183 end
@@ -190,6 +190,10 @@ module IteratorsMD
190190 As a convenience, constructing a `CartesianIndices` from an array makes a
191191 range of its indices.
192192
193+ !!! compat "Julia 1.6"
194+ The step range method `CartesianIndices((istart:istep:istop, jstart:[jstep:]jstop, ...))`
195+ requires at least Julia 1.6.
196+
193197 # Examples
194198 ```jldoctest
195199 julia> foreach(println, CartesianIndices((2, 2, 2)))
@@ -222,6 +226,15 @@ module IteratorsMD
222226
223227 julia> cartesian[4]
224228 CartesianIndex(1, 2)
229+
230+ julia> cartesian = CartesianIndices((1:2:5, 1:2))
231+ 3×2 CartesianIndices{2, Tuple{StepRange{Int64, Int64}, UnitRange{Int64}}}:
232+ CartesianIndex(1, 1) CartesianIndex(1, 2)
233+ CartesianIndex(3, 1) CartesianIndex(3, 2)
234+ CartesianIndex(5, 1) CartesianIndex(5, 2)
235+
236+ julia> cartesian[2, 2]
237+ CartesianIndex(3, 2)
225238 ```
226239
227240 ## Broadcasting
@@ -248,29 +261,36 @@ module IteratorsMD
248261
249262 For cartesian to linear index conversion, see [`LinearIndices`](@ref).
250263 """
251- struct CartesianIndices{N,R<: NTuple{N,AbstractUnitRange{ Int}} } <: AbstractArray{CartesianIndex{N},N}
264+ struct CartesianIndices{N,R<: NTuple{N,OrdinalRange{Int, Int}} } <: AbstractArray{CartesianIndex{N},N}
252265 indices:: R
253266 end
254267
255268 CartesianIndices (:: Tuple{} ) = CartesianIndices {0,typeof(())} (())
256- CartesianIndices (inds:: NTuple{N,AbstractUnitRange{<:Integer}} ) where {N} =
257- CartesianIndices (map (r-> convert (AbstractUnitRange{Int}, r), inds))
269+ function CartesianIndices (inds:: NTuple{N,OrdinalRange{<:Integer, <:Integer}} ) where {N}
270+ indices = map (r-> convert (OrdinalRange{Int, Int}, r), inds)
271+ CartesianIndices {N, typeof(indices)} (indices)
272+ end
258273
259274 CartesianIndices (index:: CartesianIndex ) = CartesianIndices (index. I)
260- CartesianIndices (sz:: NTuple{N,<:Integer} ) where {N} = CartesianIndices (map (Base. OneTo, sz))
261- CartesianIndices (inds:: NTuple{N,Union{<:Integer,AbstractUnitRange{<:Integer}}} ) where {N} =
262- CartesianIndices (map (i-> first (i): last (i), inds))
275+ CartesianIndices (inds:: NTuple{N,Union{<:Integer,OrdinalRange{<:Integer}}} ) where {N} =
276+ CartesianIndices (map (_range2ind, inds))
263277
264278 CartesianIndices (A:: AbstractArray ) = CartesianIndices (axes (A))
265279
280+ _range2ind (sz:: Integer ) = Base. OneTo (sz)
281+ _range2ind (ind:: OrdinalRange ) = ind
282+
266283 """
267- (:)(I ::CartesianIndex, J ::CartesianIndex)
284+ (:)(start ::CartesianIndex, [step::CartesianIndex], stop ::CartesianIndex)
268285
269- Construct [`CartesianIndices`](@ref) from two `CartesianIndex`.
286+ Construct [`CartesianIndices`](@ref) from two `CartesianIndex` and an optional step .
270287
271288 !!! compat "Julia 1.1"
272289 This method requires at least Julia 1.1.
273290
291+ !!! compat "Julia 1.6"
292+ The step range method start:step:stop requires at least Julia 1.6.
293+
274294 # Examples
275295 ```jldoctest
276296 julia> I = CartesianIndex(2,1);
@@ -281,17 +301,26 @@ module IteratorsMD
281301 2×3 CartesianIndices{2, Tuple{UnitRange{Int64}, UnitRange{Int64}}}:
282302 CartesianIndex(2, 1) CartesianIndex(2, 2) CartesianIndex(2, 3)
283303 CartesianIndex(3, 1) CartesianIndex(3, 2) CartesianIndex(3, 3)
304+
305+ julia> I:CartesianIndex(1, 2):J
306+ 2×2 CartesianIndices{2, Tuple{StepRange{Int64, Int64}, StepRange{Int64, Int64}}}:
307+ CartesianIndex(2, 1) CartesianIndex(2, 3)
308+ CartesianIndex(3, 1) CartesianIndex(3, 3)
284309 ```
285310 """
286311 (:)(I:: CartesianIndex{N} , J:: CartesianIndex{N} ) where N =
287312 CartesianIndices (map ((i,j) -> i: j, Tuple (I), Tuple (J)))
313+ (:)(I:: CartesianIndex{N} , S:: CartesianIndex{N} , J:: CartesianIndex{N} ) where N =
314+ CartesianIndices (map ((i,s,j) -> i: s: j, Tuple (I), Tuple (S), Tuple (J)))
288315
289316 promote_rule (:: Type{CartesianIndices{N,R1}} , :: Type{CartesianIndices{N,R2}} ) where {N,R1,R2} =
290317 CartesianIndices{N,Base. indices_promote_type (R1,R2)}
291318
292319 convert (:: Type{Tuple{}} , R:: CartesianIndices{0} ) = ()
293- convert (:: Type{NTuple{N,AbstractUnitRange{Int}}} , R:: CartesianIndices{N} ) where {N} =
294- R. indices
320+ for RT in (OrdinalRange{Int, Int}, StepRange{Int, Int}, AbstractUnitRange{Int})
321+ @eval convert (:: Type{NTuple{N,$RT}} , R:: CartesianIndices{N} ) where {N} =
322+ R. indices
323+ end
295324 convert (:: Type{NTuple{N,AbstractUnitRange}} , R:: CartesianIndices{N} ) where {N} =
296325 convert (NTuple{N,AbstractUnitRange{Int}}, R)
297326 convert (:: Type{NTuple{N,UnitRange{Int}}} , R:: CartesianIndices{N} ) where {N} =
@@ -318,13 +347,9 @@ module IteratorsMD
318347 # AbstractArray implementation
319348 Base. axes (iter:: CartesianIndices{N,R} ) where {N,R} = map (Base. axes1, iter. indices)
320349 Base. IndexStyle (:: Type{CartesianIndices{N,R}} ) where {N,R} = IndexCartesian ()
321- @inline function Base. getindex (iter:: CartesianIndices{N,<:NTuple{N,Base.OneTo}} , I:: Vararg{Int, N} ) where {N}
322- @boundscheck checkbounds (iter, I... )
323- CartesianIndex (I)
324- end
325350 @inline function Base. getindex (iter:: CartesianIndices{N,R} , I:: Vararg{Int, N} ) where {N,R}
326351 @boundscheck checkbounds (iter, I... )
327- CartesianIndex (I .- first .(Base . axes1 .( iter. indices)) .+ first .(iter . indices ))
352+ CartesianIndex (getindex .( iter. indices, I ))
328353 end
329354
330355 ndims (R:: CartesianIndices ) = ndims (typeof (R))
@@ -351,37 +376,39 @@ module IteratorsMD
351376 iterfirst, iterfirst
352377 end
353378 @inline function iterate (iter:: CartesianIndices , state)
354- valid, I = __inc (state. I, first (iter). I, last (iter). I)
379+ valid, I = __inc (state. I, first (iter). I, step .(iter . indices), last (iter). I)
355380 valid || return nothing
356381 return CartesianIndex (I... ), CartesianIndex (I... )
357382 end
358383
359384 # increment & carry
360- @inline function inc (state, start, stop)
361- _, I = __inc (state, start, stop)
385+ # TODO : optimize this; it adds up about 5ns overhead
386+ @inline function inc (state, start, step, stop)
387+ _, I = __inc (state, start, step, stop)
362388 return CartesianIndex (I... )
363389 end
364390
365391 # increment post check to avoid integer overflow
366- @inline __inc (:: Tuple{} , :: Tuple{} , :: Tuple{} ) = false , ()
367- @inline function __inc (state:: Tuple{Int} , start:: Tuple{Int} , stop:: Tuple{Int} )
368- valid = state[1 ] < stop[1 ]
369- return valid, (state[1 ]+ 1 ,)
392+ @inline __inc (:: Tuple{} , :: Tuple{} , :: Tuple{} , :: Tuple{} ) = false , ()
393+ @inline function __inc (state:: Tuple{Int} , start:: Tuple{Int} , step:: Tuple{Int} , stop:: Tuple{Int} )
394+ I = state[1 ] + step[1 ]
395+ valid = I <= stop[1 ]
396+ return valid, (I, )
370397 end
371398
372- @inline function __inc (state, start, stop)
373- if state[1 ] < stop[1 ]
374- return true , (state[1 ]+ 1 , tail (state)... )
399+ @inline function __inc (state, start, step, stop)
400+ I = state[1 ] + step[1 ]
401+ if I <= stop[1 ]
402+ return true , (I, tail (state)... )
375403 end
376- valid, I = __inc (tail (state), tail (start), tail (stop))
404+ valid, I = __inc (tail (state), tail (start), tail (step), tail ( stop))
377405 return valid, (start[1 ], I... )
378406 end
379407
380408 # 0-d cartesian ranges are special-cased to iterate once and only once
381409 iterate (iter:: CartesianIndices{0} , done= false ) = done ? nothing : (CartesianIndex (), true )
382410
383- size (iter:: CartesianIndices ) = map (dimlength, first (iter). I, last (iter). I)
384- dimlength (start, stop) = stop- start+ 1
411+ size (iter:: CartesianIndices ) = map (length, iter. indices)
385412
386413 length (iter:: CartesianIndices ) = prod (size (iter))
387414
@@ -395,11 +422,8 @@ module IteratorsMD
395422 @inline to_indices (A, inds, I:: Tuple{CartesianIndices{0},Vararg{Any}} ) =
396423 (first (I), to_indices (A, inds, tail (I))... )
397424
398- @inline function in (i:: CartesianIndex{N} , r:: CartesianIndices{N} ) where {N}
399- _in (true , i. I, first (r). I, last (r). I)
400- end
401- _in (b, :: Tuple{} , :: Tuple{} , :: Tuple{} ) = b
402- @inline _in (b, i, start, stop) = _in (b & (start[1 ] <= i[1 ] <= stop[1 ]), tail (i), tail (start), tail (stop))
425+ @inline in (i:: CartesianIndex , r:: CartesianIndices ) = false
426+ @inline in (i:: CartesianIndex{N} , r:: CartesianIndices{N} ) where {N} = all (map (in, i. I, r. indices))
403427
404428 simd_outer_range (iter:: CartesianIndices{0} ) = iter
405429 function simd_outer_range (iter:: CartesianIndices )
@@ -448,36 +472,38 @@ module IteratorsMD
448472 iterfirst, iterfirst
449473 end
450474 @inline function iterate (r:: Reverse{<:CartesianIndices} , state)
451- valid, I = __dec (state. I, last (r. itr). I, first (r. itr). I)
475+ valid, I = __dec (state. I, last (r. itr). I, step .(r . itr . indices), first (r. itr). I)
452476 valid || return nothing
453477 return CartesianIndex (I... ), CartesianIndex (I... )
454478 end
455479
456480 # decrement & carry
457- @inline function dec (state, start, stop)
458- _, I = __dec (state, start, stop)
481+ @inline function dec (state, start, step, stop)
482+ _, I = __dec (state, start, step, stop)
459483 return CartesianIndex (I... )
460484 end
461485
462486 # decrement post check to avoid integer overflow
463- @inline __dec (:: Tuple{} , :: Tuple{} , :: Tuple{} ) = false , ()
464- @inline function __dec (state:: Tuple{Int} , start:: Tuple{Int} , stop:: Tuple{Int} )
465- valid = state[1 ] > stop[1 ]
466- return valid, (state[1 ]- 1 ,)
487+ @inline __dec (:: Tuple{} , :: Tuple{} , :: Tuple{} , :: Tuple{} ) = false , ()
488+ @inline function __dec (state:: Tuple{Int} , start:: Tuple{Int} , step:: Tuple{Int} , stop:: Tuple{Int} )
489+ I = state[1 ] - step[1 ]
490+ valid = I >= stop[1 ]
491+ return valid, (I,)
467492 end
468493
469- @inline function __dec (state, start, stop)
470- if state[1 ] > stop[1 ]
471- return true , (state[1 ]- 1 , tail (state)... )
494+ @inline function __dec (state, start, step, stop)
495+ I = state[1 ] - step[1 ]
496+ if I >= stop[1 ]
497+ return true , (I, tail (state)... )
472498 end
473- valid, I = __dec (tail (state), tail (start), tail (stop))
499+ valid, I = __dec (tail (state), tail (start), tail (step), tail ( stop))
474500 return valid, (start[1 ], I... )
475501 end
476502
477503 # 0-d cartesian ranges are special-cased to iterate once and only once
478504 iterate (iter:: Reverse{<:CartesianIndices{0}} , state= false ) = state ? nothing : (CartesianIndex (), true )
479505
480- Base. LinearIndices (inds:: CartesianIndices{N,R} ) where {N,R} = LinearIndices {N,R} ( inds. indices )
506+ Base. LinearIndices (inds:: CartesianIndices{N,R} ) where {N,R} = LinearIndices ( axes ( inds) )
481507
482508 # array operations
483509 Base. intersect (a:: CartesianIndices{N} , b:: CartesianIndices{N} ) where N =
0 commit comments