@@ -979,6 +979,25 @@ impl FusedIterator for Components<'_> {}
979979impl < ' a > cmp:: PartialEq for Components < ' a > {
980980 #[ inline]
981981 fn eq ( & self , other : & Components < ' a > ) -> bool {
982+ let Components { path : _, front : _, back : _, has_physical_root : _, prefix : _ } = self ;
983+
984+ // Fast path for exact matches, e.g. for hashmap lookups.
985+ // Don't explicitly compare the prefix or has_physical_root fields since they'll
986+ // either be covered by the `path` buffer or are only relevant for `prefix_verbatim()`.
987+ if self . path . len ( ) == other. path . len ( )
988+ && self . front == other. front
989+ && self . back == State :: Body
990+ && other. back == State :: Body
991+ && self . prefix_verbatim ( ) == other. prefix_verbatim ( )
992+ {
993+ // possible future improvement: this could bail out earlier if there were a
994+ // reverse memcmp/bcmp comparing back to front
995+ if self . path == other. path {
996+ return true ;
997+ }
998+ }
999+
1000+ // compare back to front since absolute paths often share long prefixes
9821001 Iterator :: eq ( self . clone ( ) . rev ( ) , other. clone ( ) . rev ( ) )
9831002 }
9841003}
@@ -1013,13 +1032,12 @@ fn compare_components(mut left: Components<'_>, mut right: Components<'_>) -> cm
10131032 // The fast path isn't taken for paths with a PrefixComponent to avoid backtracking into
10141033 // the middle of one
10151034 if left. prefix . is_none ( ) && right. prefix . is_none ( ) && left. front == right. front {
1016- // this might benefit from a [u8]::first_mismatch simd implementation, if it existed
1017- let first_difference =
1018- match left. path . iter ( ) . zip ( right. path . iter ( ) ) . position ( |( & a, & b) | a != b) {
1019- None if left. path . len ( ) == right. path . len ( ) => return cmp:: Ordering :: Equal ,
1020- None => left. path . len ( ) . min ( right. path . len ( ) ) ,
1021- Some ( diff) => diff,
1022- } ;
1035+ // possible future improvement: a [u8]::first_mismatch simd implementation
1036+ let first_difference = match left. path . iter ( ) . zip ( right. path ) . position ( |( & a, & b) | a != b) {
1037+ None if left. path . len ( ) == right. path . len ( ) => return cmp:: Ordering :: Equal ,
1038+ None => left. path . len ( ) . min ( right. path . len ( ) ) ,
1039+ Some ( diff) => diff,
1040+ } ;
10231041
10241042 if let Some ( previous_sep) =
10251043 left. path [ ..first_difference] . iter ( ) . rposition ( |& b| left. is_sep_byte ( b) )
@@ -2873,9 +2891,43 @@ impl cmp::PartialEq for Path {
28732891#[ stable( feature = "rust1" , since = "1.0.0" ) ]
28742892impl Hash for Path {
28752893 fn hash < H : Hasher > ( & self , h : & mut H ) {
2876- for component in self . components ( ) {
2877- component. hash ( h) ;
2894+ let bytes = self . as_u8_slice ( ) ;
2895+ let prefix_len = match parse_prefix ( & self . inner ) {
2896+ Some ( prefix) => {
2897+ prefix. hash ( h) ;
2898+ prefix. len ( )
2899+ }
2900+ None => 0 ,
2901+ } ;
2902+ let bytes = & bytes[ prefix_len..] ;
2903+
2904+ let mut component_start = 0 ;
2905+ let mut bytes_hashed = 0 ;
2906+
2907+ for i in 0 ..bytes. len ( ) {
2908+ if is_sep_byte ( bytes[ i] ) {
2909+ if i > component_start {
2910+ let to_hash = & bytes[ component_start..i] ;
2911+ h. write ( to_hash) ;
2912+ bytes_hashed += to_hash. len ( ) ;
2913+ }
2914+
2915+ // skip over separator and optionally a following CurDir item
2916+ // since components() would normalize these away
2917+ component_start = i + match bytes[ i..] {
2918+ [ _, b'.' , b'/' , ..] | [ _, b'.' ] => 2 ,
2919+ _ => 1 ,
2920+ } ;
2921+ }
2922+ }
2923+
2924+ if component_start < bytes. len ( ) {
2925+ let to_hash = & bytes[ component_start..] ;
2926+ h. write ( to_hash) ;
2927+ bytes_hashed += to_hash. len ( ) ;
28782928 }
2929+
2930+ h. write_usize ( bytes_hashed) ;
28792931 }
28802932}
28812933
0 commit comments