@@ -631,46 +631,100 @@ firstindex(::UnitRange) = 1
631
631
firstindex (:: StepRange ) = 1
632
632
firstindex (:: LinRange ) = 1
633
633
634
- length (r:: AbstractUnitRange ) = Integer (last (r) - first (r) + step (r))
634
+ # n.b. checked_length for these is defined iff checked_add and checked_sub are
635
+ # defined between the relevant types
636
+ function checked_length (r:: OrdinalRange{T} ) where T
637
+ s = step (r)
638
+ # s != 0, by construction, but avoids the division error later
639
+ start = first (r)
640
+ if s == zero (s) || isempty (r)
641
+ return Integer (start - start + zero (s))
642
+ end
643
+ return Integer (div (checked_add (checked_sub (last (r), start), s, s)))
644
+ end
645
+
646
+ function checked_length (r:: AbstractUnitRange{T} ) where T
647
+ # compiler optimization: remove dead cases from above
648
+ if isempty (r)
649
+ return Integer (first (r) - first (r))
650
+ end
651
+ a = Integer (checked_add (checked_sub (last (r), first (r))))
652
+ return a + one (a)
653
+ end
654
+
655
+ function length (r:: OrdinalRange{T} ) where T
656
+ s = step (r)
657
+ # s != 0, by construction, but avoids the division error later
658
+ start = first (r)
659
+ if s == zero (s) || isempty (r)
660
+ return Integer (start - start + zero (s))
661
+ end
662
+ return Integer (div (last (r) - start + s, s))
663
+ end
664
+
665
+ function length (r:: AbstractUnitRange{T} ) where T
666
+ @_inline_meta
667
+ a = Integer (last (r) - first (r)) # even when isempty, by construction (with overflow)
668
+ return a + one (a)
669
+ end
670
+
635
671
length (r:: OneTo ) = Integer (r. stop - zero (r. stop))
636
672
length (r:: StepRangeLen ) = r. len
637
673
length (r:: LinRange ) = r. len
638
- length (r:: StepRange ) = Integer (div (r. stop - r. start + r. step, r. step))
639
674
640
- # compile optimizations for which promote_type(T, Int) = T
641
- let bigint = Union{Int,UInt,Int64,UInt64,Int128,UInt128}
675
+ let bigints = Union{Int, UInt, Int64, UInt64, Int128, UInt128}
642
676
global length
643
- function length (r:: StepRange{T} ) where T<: bigint
644
- step = r. step
645
- diff = r. stop - r. start
646
- step == 0 && return zero (T) # unreachable, by construction, but avoids the error case here later
677
+ # compile optimization for which promote_type(T, Int) == T
678
+ length (r:: OneTo{T} ) where {T<: bigints } = r. stop
679
+ # slightly more accurate length and checked_length in extreme cases
680
+ # (near typemax) for types with known `unsigned` functions
681
+ function length (r:: OrdinalRange{T} ) where T<: bigints
682
+ s = step (r)
683
+ s == zero (s) && return zero (T) # unreachable, by construction, but avoids the error case here later
647
684
isempty (r) && return zero (T)
648
- if - 1 <= step <= 1 || step == - step || step isa Unsigned # n.b. !(step isa T)
649
- # if |step| > 1, diff might have overflowed, but unsigned(diff)÷step should
650
- # therefore still be valid (if the result is representable at all)
651
- return div (diff, step) % T + one (T)
652
- elseif step < 0
653
- return div (unsigned (- diff), - step) % T + one (T)
685
+ diff = last (r) - first (r)
686
+ # if |s| > 1, diff might have overflowed, but unsigned(diff)÷s should
687
+ # therefore still be valid (if the result is representable at all)
688
+ # n.b. !(s isa T)
689
+ if s isa Unsigned || - 1 <= s <= 1 || s == - s
690
+ a = div (diff, s)
691
+ elseif s < 0
692
+ a = div (unsigned (- diff), - s) % typeof (diff)
654
693
else
655
- return div (unsigned (diff), step ) % T + one (T )
694
+ a = div (unsigned (diff), s ) % typeof (diff )
656
695
end
696
+ return Integer (a) + one (a)
657
697
end
658
-
659
- function length (r:: AbstractUnitRange{T} ) where T<: bigint
660
- @_inline_meta
661
- return last (r) - first (r) + one (T) # even when isempty, by construction (with overflow)
698
+ function checked_length (r:: OrdinalRange{T} ) where T<: bigints
699
+ s = step (r)
700
+ s == zero (s) && return zero (T) # unreachable, by construction, but avoids the error case here later
701
+ isempty (r) && return zero (T)
702
+ stop, start = last (r), first (r)
703
+ # n.b. !(s isa T)
704
+ if s > 1
705
+ diff = stop - start
706
+ a = convert (T, div (unsigned (diff), s))
707
+ elseif s < - 1
708
+ diff = start - stop
709
+ a = convert (T, div (unsigned (diff), - s))
710
+ elseif s > 0
711
+ a = div (checked_sub (stop, start), s)
712
+ else
713
+ a = div (checked_sub (start, stop), - s)
714
+ end
715
+ return checked_add (a, one (a))
662
716
end
663
- length (r:: OneTo{T} ) where {T<: bigint } = r. stop
664
717
end
665
718
666
719
# some special cases to favor default Int type
667
- let smallint = (Int === Int64 ?
668
- Union{Int8,UInt8,Int16,UInt16,Int32,UInt32} :
669
- Union{Int8,UInt8,Int16,UInt16})
720
+ let smallints = (Int === Int64 ?
721
+ Union{Int8, UInt8, Int16, UInt16, Int32, UInt32} :
722
+ Union{Int8, UInt8, Int16, UInt16})
670
723
global length
671
- length (r:: StepRange{<:smallint} ) = div (Int (r. stop) - Int (r. start) + r. step, r. step) # n.b. !(step isa T)
672
- length (r:: AbstractUnitRange{<:smallint} ) = Int (last (r)) - Int (first (r)) + 1
673
- length (r:: OneTo{<:smallint} ) = Int (r. stop)
724
+ # n.b. !(step isa T)
725
+ length (r:: OrdinalRange{<:smallints} ) = div (Int (last (r)) - Int (first (r)) + step (r), step (r))
726
+ length (r:: AbstractUnitRange{<:smallints} ) = Int (last (r)) - Int (first (r)) + 1
727
+ length (r:: OneTo{<:smallints} ) = Int (r. stop)
674
728
end
675
729
676
730
first (r:: OrdinalRange{T} ) where {T} = convert (T, r. start)
0 commit comments