@@ -979,6 +979,25 @@ impl FusedIterator for Components<'_> {}
979
979
impl < ' a > cmp:: PartialEq for Components < ' a > {
980
980
#[ inline]
981
981
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
982
1001
Iterator :: eq ( self . clone ( ) . rev ( ) , other. clone ( ) . rev ( ) )
983
1002
}
984
1003
}
@@ -1013,13 +1032,12 @@ fn compare_components(mut left: Components<'_>, mut right: Components<'_>) -> cm
1013
1032
// The fast path isn't taken for paths with a PrefixComponent to avoid backtracking into
1014
1033
// the middle of one
1015
1034
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
+ } ;
1023
1041
1024
1042
if let Some ( previous_sep) =
1025
1043
left. path [ ..first_difference] . iter ( ) . rposition ( |& b| left. is_sep_byte ( b) )
@@ -2873,9 +2891,43 @@ impl cmp::PartialEq for Path {
2873
2891
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
2874
2892
impl Hash for Path {
2875
2893
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 ( ) ;
2878
2928
}
2929
+
2930
+ h. write_usize ( bytes_hashed) ;
2879
2931
}
2880
2932
}
2881
2933
0 commit comments