@@ -5,6 +5,7 @@ use crate::ascii;
55use  crate :: cmp:: { self ,  BytewiseEq ,  Ordering } ; 
66use  crate :: intrinsics:: compare_bytes; 
77use  crate :: num:: NonZero ; 
8+ use  crate :: ops:: ControlFlow ; 
89
910#[ stable( feature = "rust1" ,  since = "1.0.0" ) ]  
1011impl < T ,  U >  PartialEq < [ U ] >  for  [ T ] 
@@ -31,12 +32,64 @@ impl<T: Ord> Ord for [T] {
3132    } 
3233} 
3334
35+ #[ inline]  
36+ fn  as_underlying ( x :  ControlFlow < bool > )  -> u8  { 
37+     // SAFETY: This will only compile if `bool` and `ControlFlow<bool>` have the same 
38+     // size (which isn't guaranteed but this is libcore). Because they have the same 
39+     // size, it's a niched implementation, which in one byte means there can't be 
40+     // any uninitialized memory. The callers then only check for `0` or `1` from this, 
41+     // which must necessarily match the `Break` variant, and we're fine no matter 
42+     // what ends up getting picked as the value representing `Continue(())`. 
43+     unsafe  {  crate :: mem:: transmute ( x)  } 
44+ } 
45+ 
3446/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). 
3547#[ stable( feature = "rust1" ,  since = "1.0.0" ) ]  
3648impl < T :  PartialOrd >  PartialOrd  for  [ T ]  { 
49+     #[ inline]  
3750    fn  partial_cmp ( & self ,  other :  & [ T ] )  -> Option < Ordering >  { 
3851        SlicePartialOrd :: partial_compare ( self ,  other) 
3952    } 
53+     #[ inline]  
54+     fn  lt ( & self ,  other :  & Self )  -> bool  { 
55+         // This is certainly not the obvious way to implement these methods. 
56+         // Unfortunately, using anything that looks at the discriminant means that 
57+         // LLVM sees a check for `2` (aka `ControlFlow<bool>::Continue(())`) and 
58+         // gets very distracted by that, ending up generating extraneous code. 
59+         // This should be changed to something simpler once either LLVM is smarter, 
60+         // see <https://github.com/llvm/llvm-project/issues/132678>, or we generate 
61+         // niche discriminant checks in a way that doesn't trigger it. 
62+ 
63+         as_underlying ( self . __chaining_lt ( other) )  == 1 
64+     } 
65+     #[ inline]  
66+     fn  le ( & self ,  other :  & Self )  -> bool  { 
67+         as_underlying ( self . __chaining_le ( other) )  != 0 
68+     } 
69+     #[ inline]  
70+     fn  gt ( & self ,  other :  & Self )  -> bool  { 
71+         as_underlying ( self . __chaining_gt ( other) )  == 1 
72+     } 
73+     #[ inline]  
74+     fn  ge ( & self ,  other :  & Self )  -> bool  { 
75+         as_underlying ( self . __chaining_ge ( other) )  != 0 
76+     } 
77+     #[ inline]  
78+     fn  __chaining_lt ( & self ,  other :  & Self )  -> ControlFlow < bool >  { 
79+         SliceChain :: chaining_lt ( self ,  other) 
80+     } 
81+     #[ inline]  
82+     fn  __chaining_le ( & self ,  other :  & Self )  -> ControlFlow < bool >  { 
83+         SliceChain :: chaining_le ( self ,  other) 
84+     } 
85+     #[ inline]  
86+     fn  __chaining_gt ( & self ,  other :  & Self )  -> ControlFlow < bool >  { 
87+         SliceChain :: chaining_gt ( self ,  other) 
88+     } 
89+     #[ inline]  
90+     fn  __chaining_ge ( & self ,  other :  & Self )  -> ControlFlow < bool >  { 
91+         SliceChain :: chaining_ge ( self ,  other) 
92+     } 
4093} 
4194
4295#[ doc( hidden) ]  
@@ -99,24 +152,63 @@ trait SlicePartialOrd: Sized {
99152    fn  partial_compare ( left :  & [ Self ] ,  right :  & [ Self ] )  -> Option < Ordering > ; 
100153} 
101154
155+ #[ doc( hidden) ]  
156+ // intermediate trait for specialization of slice's PartialOrd chaining methods 
157+ trait  SliceChain :  Sized  { 
158+     fn  chaining_lt ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool > ; 
159+     fn  chaining_le ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool > ; 
160+     fn  chaining_gt ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool > ; 
161+     fn  chaining_ge ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool > ; 
162+ } 
163+ 
164+ type  AlwaysBreak < B >  = ControlFlow < B ,  crate :: convert:: Infallible > ; 
165+ 
102166impl < A :  PartialOrd >  SlicePartialOrd  for  A  { 
103167    default  fn  partial_compare ( left :  & [ A ] ,  right :  & [ A ] )  -> Option < Ordering >  { 
104-         let  l = cmp:: min ( left. len ( ) ,  right. len ( ) ) ; 
105- 
106-         // Slice to the loop iteration range to enable bound check 
107-         // elimination in the compiler 
108-         let  lhs = & left[ ..l] ; 
109-         let  rhs = & right[ ..l] ; 
168+         let  elem_chain = |a,  b| match  PartialOrd :: partial_cmp ( a,  b)  { 
169+             Some ( Ordering :: Equal )  => ControlFlow :: Continue ( ( ) ) , 
170+             non_eq => ControlFlow :: Break ( non_eq) , 
171+         } ; 
172+         let  len_chain = |a :  & _ ,  b :  & _ | ControlFlow :: Break ( usize:: partial_cmp ( a,  b) ) ; 
173+         let  AlwaysBreak :: Break ( b)  = chaining_impl ( left,  right,  elem_chain,  len_chain) ; 
174+         b
175+     } 
176+ } 
110177
111-         for  i in  0 ..l { 
112-             match  lhs[ i] . partial_cmp ( & rhs[ i] )  { 
113-                 Some ( Ordering :: Equal )  => ( ) , 
114-                 non_eq => return  non_eq, 
115-             } 
116-         } 
178+ impl < A :  PartialOrd >  SliceChain  for  A  { 
179+     default  fn  chaining_lt ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool >  { 
180+         chaining_impl ( left,  right,  PartialOrd :: __chaining_lt,  usize:: __chaining_lt) 
181+     } 
182+     default  fn  chaining_le ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool >  { 
183+         chaining_impl ( left,  right,  PartialOrd :: __chaining_le,  usize:: __chaining_le) 
184+     } 
185+     default  fn  chaining_gt ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool >  { 
186+         chaining_impl ( left,  right,  PartialOrd :: __chaining_gt,  usize:: __chaining_gt) 
187+     } 
188+     default  fn  chaining_ge ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool >  { 
189+         chaining_impl ( left,  right,  PartialOrd :: __chaining_ge,  usize:: __chaining_ge) 
190+     } 
191+ } 
117192
118-         left. len ( ) . partial_cmp ( & right. len ( ) ) 
193+ #[ inline]  
194+ fn  chaining_impl < ' l ,  ' r ,  A :  PartialOrd ,  B ,  C > ( 
195+     left :  & ' l  [ A ] , 
196+     right :  & ' r  [ A ] , 
197+     elem_chain :  impl  Fn ( & ' l  A ,  & ' r  A )  -> ControlFlow < B > , 
198+     len_chain :  impl  for < ' a >  FnOnce ( & ' a  usize ,  & ' a  usize )  -> ControlFlow < B ,  C > , 
199+ )  -> ControlFlow < B ,  C >  { 
200+     let  l = cmp:: min ( left. len ( ) ,  right. len ( ) ) ; 
201+ 
202+     // Slice to the loop iteration range to enable bound check 
203+     // elimination in the compiler 
204+     let  lhs = & left[ ..l] ; 
205+     let  rhs = & right[ ..l] ; 
206+ 
207+     for  i in  0 ..l { 
208+         elem_chain ( & lhs[ i] ,  & rhs[ i] ) ?; 
119209    } 
210+ 
211+     len_chain ( & left. len ( ) ,  & right. len ( ) ) 
120212} 
121213
122214// This is the impl that we would like to have. Unfortunately it's not sound. 
@@ -165,21 +257,13 @@ trait SliceOrd: Sized {
165257
166258impl < A :  Ord >  SliceOrd  for  A  { 
167259    default  fn  compare ( left :  & [ Self ] ,  right :  & [ Self ] )  -> Ordering  { 
168-         let  l = cmp:: min ( left. len ( ) ,  right. len ( ) ) ; 
169- 
170-         // Slice to the loop iteration range to enable bound check 
171-         // elimination in the compiler 
172-         let  lhs = & left[ ..l] ; 
173-         let  rhs = & right[ ..l] ; 
174- 
175-         for  i in  0 ..l { 
176-             match  lhs[ i] . cmp ( & rhs[ i] )  { 
177-                 Ordering :: Equal  => ( ) , 
178-                 non_eq => return  non_eq, 
179-             } 
180-         } 
181- 
182-         left. len ( ) . cmp ( & right. len ( ) ) 
260+         let  elem_chain = |a,  b| match  Ord :: cmp ( a,  b)  { 
261+             Ordering :: Equal  => ControlFlow :: Continue ( ( ) ) , 
262+             non_eq => ControlFlow :: Break ( non_eq) , 
263+         } ; 
264+         let  len_chain = |a :  & _ ,  b :  & _ | ControlFlow :: Break ( usize:: cmp ( a,  b) ) ; 
265+         let  AlwaysBreak :: Break ( b)  = chaining_impl ( left,  right,  elem_chain,  len_chain) ; 
266+         b
183267    } 
184268} 
185269
@@ -191,7 +275,7 @@ impl<A: Ord> SliceOrd for A {
191275/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same 
192276///   value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`. 
193277#[ rustc_specialization_trait]  
194- unsafe  trait  UnsignedBytewiseOrd  { } 
278+ unsafe  trait  UnsignedBytewiseOrd :   Ord  { } 
195279
196280unsafe  impl  UnsignedBytewiseOrd  for  bool  { } 
197281unsafe  impl  UnsignedBytewiseOrd  for  u8  { } 
@@ -225,6 +309,38 @@ impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
225309    } 
226310} 
227311
312+ // Don't generate our own chaining loops for `memcmp`-able things either. 
313+ impl < A :  PartialOrd  + UnsignedBytewiseOrd >  SliceChain  for  A  { 
314+     #[ inline]  
315+     fn  chaining_lt ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool >  { 
316+         match  SliceOrd :: compare ( left,  right)  { 
317+             Ordering :: Equal  => ControlFlow :: Continue ( ( ) ) , 
318+             ne => ControlFlow :: Break ( ne. is_lt ( ) ) , 
319+         } 
320+     } 
321+     #[ inline]  
322+     fn  chaining_le ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool >  { 
323+         match  SliceOrd :: compare ( left,  right)  { 
324+             Ordering :: Equal  => ControlFlow :: Continue ( ( ) ) , 
325+             ne => ControlFlow :: Break ( ne. is_le ( ) ) , 
326+         } 
327+     } 
328+     #[ inline]  
329+     fn  chaining_gt ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool >  { 
330+         match  SliceOrd :: compare ( left,  right)  { 
331+             Ordering :: Equal  => ControlFlow :: Continue ( ( ) ) , 
332+             ne => ControlFlow :: Break ( ne. is_gt ( ) ) , 
333+         } 
334+     } 
335+     #[ inline]  
336+     fn  chaining_ge ( left :  & [ Self ] ,  right :  & [ Self ] )  -> ControlFlow < bool >  { 
337+         match  SliceOrd :: compare ( left,  right)  { 
338+             Ordering :: Equal  => ControlFlow :: Continue ( ( ) ) , 
339+             ne => ControlFlow :: Break ( ne. is_ge ( ) ) , 
340+         } 
341+     } 
342+ } 
343+ 
228344pub ( super )  trait  SliceContains :  Sized  { 
229345    fn  slice_contains ( & self ,  x :  & [ Self ] )  -> bool ; 
230346} 
0 commit comments