5
5
If `first` of an instance of type `T` is known at compile time, return it.
6
6
Otherwise, return `nothing`.
7
7
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
+ ```
10
15
"""
11
16
known_first (x) = known_first (typeof (x))
12
17
function known_first (:: Type{T} ) where {T}
@@ -24,9 +29,14 @@ known_first(::Type{Base.OneTo{T}}) where {T} = one(T)
24
29
If `last` of an instance of type `T` is known at compile time, return it.
25
30
Otherwise, return `nothing`.
26
31
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
+ ```
30
40
"""
31
41
known_last (x) = known_last (typeof (x))
32
42
function known_last (:: Type{T} ) where {T}
43
53
If `step` of an instance of type `T` is known at compile time, return it.
44
54
Otherwise, return `nothing`.
45
55
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
+ ```
48
64
"""
49
65
known_step (x) = known_step (typeof (x))
50
66
function known_step (:: Type{T} ) where {T}
@@ -65,20 +81,15 @@ at compile time. An `OptionallyStaticUnitRange` is intended to be constructed in
65
81
from other valid indices. Therefore, users should not expect the same checks are used
66
82
to ensure construction of a valid `OptionallyStaticUnitRange` as a `UnitRange`.
67
83
"""
68
- struct OptionallyStaticUnitRange{F<: Integer ,L<: Integer } <: AbstractUnitRange{Int}
84
+ struct OptionallyStaticUnitRange{F<: CanonicalInt ,L<: CanonicalInt } <: AbstractUnitRange{Int}
69
85
start:: F
70
86
stop:: L
71
87
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))
82
93
end
83
94
84
95
function OptionallyStaticUnitRange {F,L} (x:: AbstractRange ) where {F,L}
@@ -138,24 +149,18 @@ julia> ArrayInterface.OptionallyStaticStepRange(x, x, 10)
138
149
ArrayInterface.StaticInt{2}():ArrayInterface.StaticInt{2}():10
139
150
```
140
151
"""
141
- struct OptionallyStaticStepRange{F<: Integer ,S<: Integer ,L<: Integer } <: OrdinalRange{Int,Int}
152
+ struct OptionallyStaticStepRange{F<: CanonicalInt ,S<: CanonicalInt ,L<: CanonicalInt } <: OrdinalRange{Int,Int}
142
153
start:: F
143
154
step:: S
144
155
stop:: L
145
156
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))
157
163
end
158
-
159
164
function OptionallyStaticStepRange (x:: AbstractRange )
160
165
return OptionallyStaticStepRange (static_first (x), static_step (x), static_last (x))
161
166
end
277
282
unsafe_isempty_one_to (lst) = lst <= zero (lst)
278
283
unsafe_isempty_unit_range (fst, lst) = fst > lst
279
284
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
-
296
285
@propagate_inbounds function Base. getindex (
297
286
r:: OptionallyStaticUnitRange ,
298
287
s:: AbstractUnitRange{<:Integer} ,
@@ -347,81 +336,54 @@ end
347
336
return x
348
337
end
349
338
350
- # ##
351
- # ## length
352
- # ##
339
+ # # length
353
340
@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))
365
342
end
366
343
367
344
@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))
384
346
end
385
347
386
- function Base. length (r:: OptionallyStaticUnitRange )
348
+ @inline function Base. length (r:: OptionallyStaticUnitRange )
387
349
if isempty (r)
388
350
return 0
389
351
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))
395
353
end
396
354
end
397
355
398
- function Base. length (r:: OptionallyStaticStepRange )
356
+ @inline function Base. length (r:: OptionallyStaticStepRange )
399
357
if isempty (r)
400
358
return 0
401
359
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))
411
361
end
412
362
end
413
363
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
415
380
381
+ Base. AbstractUnitRange {Int} (r:: OptionallyStaticUnitRange ) = r
416
382
function 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))
419
385
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))
425
387
end
426
388
end
427
389
0 commit comments