@@ -2787,37 +2787,56 @@ impl<T> [T] {
27872787 where
27882788 F : FnMut ( & ' a T ) -> Ordering ,
27892789 {
2790+ // If T is a ZST, we assume that f is a constant function.
2791+ // We do so because:
2792+ // 1. ZSTs can only have one inhabitant
2793+ // 2. We assume that f doesn't compare the address of the reference
2794+ // passed, but only the value pointed to.
2795+ // 3. We assume f's output to be entirely determined by its input
2796+ if T :: IS_ZST {
2797+ let res = if self . len ( ) == 0 {
2798+ Err ( 0 )
2799+ } else {
2800+ match f ( & self [ 0 ] ) {
2801+ Less => Err ( self . len ( ) ) ,
2802+ Equal => Ok ( 0 ) ,
2803+ Greater => Err ( 0 ) ,
2804+ }
2805+ } ;
2806+ return res;
2807+ }
2808+ // Now we can assume that T is not a ZST, so self.len() <= isize::MAX
27902809 // INVARIANTS:
2791- // - 0 <= left <= left + size = right <= self.len()
2810+ // - 0 <= left <= right <= self.len() <= isize::MAX
27922811 // - f returns Less for everything in self[..left]
27932812 // - f returns Greater for everything in self[right..]
2794- let mut size = self . len ( ) ;
2813+ let mut right = self . len ( ) ;
27952814 let mut left = 0 ;
2796- let mut right = size;
27972815 while left < right {
2798- let mid = left + size / 2 ;
2816+ // left + right <= 2*isize::MAX < usize::MAX
2817+ // so the addition won't overflow
2818+ let mid = ( left + right) / 2 ;
27992819
2800- // SAFETY: the while condition means `size` is strictly positive, so
2801- // `size/2 < size`. Thus `left + size/2 < left + size`, which
2802- // coupled with the `left + size <= self.len()` invariant means
2803- // we have `left + size/2 < self.len()`, and this is in-bounds.
2820+ // SAFETY: We have that left < right, so
2821+ // 0 <= left <= mid < right <= self.len()
2822+ // and the indexing is in-bounds.
28042823 let cmp = f ( unsafe { self . get_unchecked ( mid) } ) ;
28052824
28062825 // This control flow produces conditional moves, which results in
28072826 // fewer branches and instructions than if/else or matching on
28082827 // cmp::Ordering.
28092828 // This is x86 asm for u8: https://rust.godbolt.org/z/698eYffTx.
2829+ // (Note: the code has slightly changed since this comment but the
2830+ // reasoning remains the same.)
2831+
28102832 left = if cmp == Less { mid + 1 } else { left } ;
28112833 right = if cmp == Greater { mid } else { right } ;
28122834 if cmp == Equal {
28132835 // SAFETY: same as the `get_unchecked` above
28142836 unsafe { hint:: assert_unchecked ( mid < self . len ( ) ) } ;
28152837 return Ok ( mid) ;
28162838 }
2817-
2818- size = right - left;
28192839 }
2820-
28212840 // SAFETY: directly true from the overall invariant.
28222841 // Note that this is `<=`, unlike the assume in the `Ok` path.
28232842 unsafe { hint:: assert_unchecked ( left <= self . len ( ) ) } ;
0 commit comments