@@ -962,16 +962,49 @@ impl cmp::Eq for Components<'_> {}
962962impl < ' a > cmp:: PartialOrd for Components < ' a > {
963963 #[ inline]
964964 fn partial_cmp ( & self , other : & Components < ' a > ) -> Option < cmp:: Ordering > {
965- Iterator :: partial_cmp ( self . clone ( ) , other. clone ( ) )
965+ Some ( compare_components ( self . clone ( ) , other. clone ( ) ) )
966966 }
967967}
968968
969969#[ stable( feature = "rust1" , since = "1.0.0" ) ]
970970impl cmp:: Ord for Components < ' _ > {
971971 #[ inline]
972972 fn cmp ( & self , other : & Self ) -> cmp:: Ordering {
973- Iterator :: cmp ( self . clone ( ) , other. clone ( ) )
973+ compare_components ( self . clone ( ) , other. clone ( ) )
974+ }
975+ }
976+
977+ fn compare_components ( mut left : Components < ' _ > , mut right : Components < ' _ > ) -> cmp:: Ordering {
978+ // Fast path for long shared prefixes
979+ //
980+ // - compare raw bytes to find first mismatch
981+ // - backtrack to find separator before mismatch to avoid ambiguous parsings of '.' or '..' characters
982+ // - if found update state to only do a component-wise comparison on the remainder,
983+ // otherwise do it on the full path
984+ //
985+ // The fast path isn't taken for paths with a PrefixComponent to avoid backtracking into
986+ // the middle of one
987+ if left. prefix . is_none ( ) && right. prefix . is_none ( ) && left. front == right. front {
988+ // this might benefit from a [u8]::first_mismatch simd implementation, if it existed
989+ let first_difference =
990+ match left. path . iter ( ) . zip ( right. path . iter ( ) ) . position ( |( & a, & b) | a != b) {
991+ None if left. path . len ( ) == right. path . len ( ) => return cmp:: Ordering :: Equal ,
992+ None => left. path . len ( ) . min ( right. path . len ( ) ) ,
993+ Some ( diff) => diff,
994+ } ;
995+
996+ if let Some ( previous_sep) =
997+ left. path [ ..first_difference] . iter ( ) . rposition ( |& b| left. is_sep_byte ( b) )
998+ {
999+ let mismatched_component_start = previous_sep + 1 ;
1000+ left. path = & left. path [ mismatched_component_start..] ;
1001+ left. front = State :: Body ;
1002+ right. path = & right. path [ mismatched_component_start..] ;
1003+ right. front = State :: Body ;
1004+ }
9741005 }
1006+
1007+ Iterator :: cmp ( left, right)
9751008}
9761009
9771010/// An iterator over [`Path`] and its ancestors.
@@ -1704,15 +1737,15 @@ impl cmp::Eq for PathBuf {}
17041737impl cmp:: PartialOrd for PathBuf {
17051738 #[ inline]
17061739 fn partial_cmp ( & self , other : & PathBuf ) -> Option < cmp:: Ordering > {
1707- self . components ( ) . partial_cmp ( other. components ( ) )
1740+ Some ( compare_components ( self . components ( ) , other. components ( ) ) )
17081741 }
17091742}
17101743
17111744#[ stable( feature = "rust1" , since = "1.0.0" ) ]
17121745impl cmp:: Ord for PathBuf {
17131746 #[ inline]
17141747 fn cmp ( & self , other : & PathBuf ) -> cmp:: Ordering {
1715- self . components ( ) . cmp ( other. components ( ) )
1748+ compare_components ( self . components ( ) , other. components ( ) )
17161749 }
17171750}
17181751
@@ -2706,15 +2739,15 @@ impl cmp::Eq for Path {}
27062739impl cmp:: PartialOrd for Path {
27072740 #[ inline]
27082741 fn partial_cmp ( & self , other : & Path ) -> Option < cmp:: Ordering > {
2709- self . components ( ) . partial_cmp ( other. components ( ) )
2742+ Some ( compare_components ( self . components ( ) , other. components ( ) ) )
27102743 }
27112744}
27122745
27132746#[ stable( feature = "rust1" , since = "1.0.0" ) ]
27142747impl cmp:: Ord for Path {
27152748 #[ inline]
27162749 fn cmp ( & self , other : & Path ) -> cmp:: Ordering {
2717- self . components ( ) . cmp ( other. components ( ) )
2750+ compare_components ( self . components ( ) , other. components ( ) )
27182751 }
27192752}
27202753
0 commit comments