55If `first` of an instance of type `T` is known at compile time, return it.
66Otherwise, return `nothing`.
77
8- @test isnothing(known_first(typeof(1:4)))
9- @test isone(known_first(typeof(Base.OneTo(4))))
8+ ```julia
9+ julia> ArrayInterface.known_first(typeof(1:4))
10+ nothing
11+
12+ julia> ArrayInterface.known_first(typeof(Base.OneTo(4)))
13+ 1
14+ ```
1015"""
1116known_first (x) = known_first (typeof (x))
1217function known_first (:: Type{T} ) where {T}
@@ -24,9 +29,14 @@ known_first(::Type{Base.OneTo{T}}) where {T} = one(T)
2429If `last` of an instance of type `T` is known at compile time, return it.
2530Otherwise, return `nothing`.
2631
27- @test isnothing(known_last(typeof(1:4)))
28- using StaticArrays
29- @test known_last(typeof(SOneTo(4))) == 4
32+ ```julia
33+ julia> ArrayInterface.known_last(typeof(1:4))
34+ nothing
35+
36+ julia> ArrayInterface.known_first(typeof(static(1):static(4)))
37+ 4
38+
39+ ```
3040"""
3141known_last (x) = known_last (typeof (x))
3242function known_last (:: Type{T} ) where {T}
4353If `step` of an instance of type `T` is known at compile time, return it.
4454Otherwise, return `nothing`.
4555
46- @test isnothing(known_step(typeof(1:0.2:4)))
47- @test isone(known_step(typeof(1:4)))
56+ ```julia
57+ julia> ArrayInterface.known_step(typeof(1:2:8))
58+ nothing
59+
60+ julia> ArrayInterface.known_step(typeof(1:4))
61+ 1
62+
63+ ```
4864"""
4965known_step (x) = known_step (typeof (x))
5066function known_step (:: Type{T} ) where {T}
@@ -65,20 +81,15 @@ at compile time. An `OptionallyStaticUnitRange` is intended to be constructed in
6581from other valid indices. Therefore, users should not expect the same checks are used
6682to ensure construction of a valid `OptionallyStaticUnitRange` as a `UnitRange`.
6783"""
68- struct OptionallyStaticUnitRange{F<: Integer ,L<: Integer } <: AbstractUnitRange{Int}
84+ struct OptionallyStaticUnitRange{F<: CanonicalInt ,L<: CanonicalInt } <: AbstractUnitRange{Int}
6985 start:: F
7086 stop:: L
7187
72- function OptionallyStaticUnitRange (start, stop)
73- if eltype (start) <: Int
74- if eltype (stop) <: Int
75- return new {typeof(start),typeof(stop)} (start, stop)
76- else
77- return OptionallyStaticUnitRange (start, Int (stop))
78- end
79- else
80- return OptionallyStaticUnitRange (Int (start), stop)
81- end
88+ function OptionallyStaticUnitRange (start:: CanonicalInt , stop:: CanonicalInt )
89+ new {typeof(start),typeof(stop)} (start, stop)
90+ end
91+ function OptionallyStaticUnitRange (start:: Integer , stop:: Integer )
92+ OptionallyStaticUnitRange (canonicalize (start), canonicalize (stop))
8293 end
8394
8495 function OptionallyStaticUnitRange {F,L} (x:: AbstractRange ) where {F,L}
@@ -138,24 +149,18 @@ julia> ArrayInterface.OptionallyStaticStepRange(x, x, 10)
138149ArrayInterface.StaticInt{2}():ArrayInterface.StaticInt{2}():10
139150```
140151"""
141- struct OptionallyStaticStepRange{F<: Integer ,S<: Integer ,L<: Integer } <: OrdinalRange{Int,Int}
152+ struct OptionallyStaticStepRange{F<: CanonicalInt ,S<: CanonicalInt ,L<: CanonicalInt } <: OrdinalRange{Int,Int}
142153 start:: F
143154 step:: S
144155 stop:: L
145156
146- function OptionallyStaticStepRange (start, step, stop)
147- if eltype (start) <: Int
148- if eltype (stop) <: Int
149- lst = _steprange_last (start, step, stop)
150- return new {typeof(start),typeof(step),typeof(lst)} (start, step, lst)
151- else
152- return OptionallyStaticStepRange (start, step, Int (stop))
153- end
154- else
155- return OptionallyStaticStepRange (Int (start), step, stop)
156- end
157+ function OptionallyStaticStepRange (start:: CanonicalInt , step:: CanonicalInt , stop:: CanonicalInt )
158+ lst = _steprange_last (start, step, stop)
159+ new {typeof(start),typeof(step),typeof(lst)} (start, step, lst)
160+ end
161+ function OptionallyStaticStepRange (start:: Integer , step:: Integer , stop:: Integer )
162+ OptionallyStaticStepRange (canonicalize (start), canonicalize (step), canonicalize (stop))
157163 end
158-
159164 function OptionallyStaticStepRange (x:: AbstractRange )
160165 return OptionallyStaticStepRange (static_first (x), static_step (x), static_last (x))
161166 end
277282unsafe_isempty_one_to (lst) = lst <= zero (lst)
278283unsafe_isempty_unit_range (fst, lst) = fst > lst
279284
280- unsafe_length_one_to (lst:: Int ) = lst
281- unsafe_length_one_to (:: StaticInt{L} ) where {L} = L
282-
283- # TODO this should probably be renamed because the point is that it is safe
284- @inline function unsafe_length_step_range (start:: Int , step:: Int , stop:: Int )
285- if step > 1
286- return Base. checked_add (Int (div (unsigned (stop - start), step)), 1 )
287- elseif step < - 1
288- return Base. checked_add (Int (div (unsigned (start - stop), - step)), 1 )
289- elseif step > 0
290- return Base. checked_add (Int (div (Base. checked_sub (stop, start), step)), 1 )
291- else
292- return Base. checked_add (Int (div (Base. checked_sub (start, stop), - step)), 1 )
293- end
294- end
295-
296285@propagate_inbounds function Base. getindex (
297286 r:: OptionallyStaticUnitRange ,
298287 s:: AbstractUnitRange{<:Integer} ,
@@ -347,81 +336,54 @@ end
347336 return x
348337end
349338
350- # ##
351- # ## length
352- # ##
339+ # # length
353340@inline function known_length (:: Type{T} ) where {T<: OptionallyStaticUnitRange }
354- fst = known_first (T)
355- lst = known_last (T)
356- if fst === nothing || lst === nothing
357- return nothing
358- else
359- if fst === oneunit (eltype (T))
360- return unsafe_length_one_to (lst)
361- else
362- return unsafe_length_unit_range (fst, lst)
363- end
364- end
341+ return _range_length (known_first (T), known_last (T))
365342end
366343
367344@inline function known_length (:: Type{T} ) where {T<: OptionallyStaticStepRange }
368- fst = known_first (T)
369- stp = known_step (T)
370- lst = known_last (T)
371- if fst === nothing || stp === nothing || lst === nothing
372- return nothing
373- else
374- if stp === 1
375- if fst === oneunit (eltype (T))
376- return unsafe_length_one_to (lst)
377- else
378- return unsafe_length_unit_range (fst, lst)
379- end
380- else
381- return unsafe_length_step_range (fst, stp, lst)
382- end
383- end
345+ _range_length (known_first (T), known_step (T), known_last (T))
384346end
385347
386- function Base. length (r:: OptionallyStaticUnitRange )
348+ @inline function Base. length (r:: OptionallyStaticUnitRange )
387349 if isempty (r)
388350 return 0
389351 else
390- if known_first (r) === 1
391- return unsafe_length_one_to (last (r))
392- else
393- return unsafe_length_unit_range (first (r), last (r))
394- end
352+ return _range_length (static_first (r), static_last (r))
395353 end
396354end
397355
398- function Base. length (r:: OptionallyStaticStepRange )
356+ @inline function Base. length (r:: OptionallyStaticStepRange )
399357 if isempty (r)
400358 return 0
401359 else
402- if known_step (r) === 1
403- if known_first (r) === 1
404- return unsafe_length_one_to (last (r))
405- else
406- return unsafe_length_unit_range (first (r), last (r))
407- end
408- else
409- return unsafe_length_step_range (Int (first (r)), Int (step (r)), Int (last (r)))
410- end
360+ return _range_length (static_first (r), static_step (r), static_last (r))
411361 end
412362end
413363
414- unsafe_length_unit_range (start:: Integer , stop:: Integer ) = Int ((stop - start) + 1 )
364+ _range_length (:: StaticInt{1} , stop:: Integer ) = Int (stop)
365+ _range_length (start:: Integer , stop:: Integer ) = Int ((stop - start) + 1 )
366+ _range_length (start, stop) = nothing
367+ _range_length (start:: Integer , :: StaticInt{1} , stop:: Integer ) = _range_length (start, stop)
368+ @inline function _range_length (start:: Integer , step:: Integer , stop:: Integer )
369+ if step > 1
370+ return Base. checked_add (Int (div (unsigned (stop - start), step)), 1 )
371+ elseif step < - 1
372+ return Base. checked_add (Int (div (unsigned (start - stop), - step)), 1 )
373+ elseif step > 0
374+ return Base. checked_add (Int (div (Base. checked_sub (stop, start), step)), 1 )
375+ else
376+ return Base. checked_add (Int (div (Base. checked_sub (start, stop), - step)), 1 )
377+ end
378+ end
379+ _range_length (start, step, stop) = nothing
415380
381+ Base. AbstractUnitRange {Int} (r:: OptionallyStaticUnitRange ) = r
416382function Base. AbstractUnitRange {T} (r:: OptionallyStaticUnitRange ) where {T}
417- if T <: Int
418- return r
383+ if known_first (r) === 1 && T <: Integer
384+ return OneTo {T} ( last (r))
419385 else
420- if known_first (r) === 1 && T <: Integer
421- return OneTo {T} (last (r))
422- else
423- return UnitRange {T} (first (r), last (r))
424- end
386+ return UnitRange {T} (first (r), last (r))
425387 end
426388end
427389
0 commit comments