@@ -3,77 +3,152 @@ use rustc_serialize::{
3
3
opaque:: { self , EncodeResult } ,
4
4
Decodable , Encodable ,
5
5
} ;
6
+ use std:: cmp:: Ordering ;
6
7
use std:: hash:: { Hash , Hasher } ;
7
- use std:: mem;
8
8
9
- #[ derive( Eq , PartialEq , Ord , PartialOrd , Debug , Clone , Copy ) ]
10
- pub struct Fingerprint ( u64 , u64 ) ;
9
+ #[ cfg( test) ]
10
+ mod tests;
11
+
12
+ // Use `[u8; 16]` representation since it imposes no alignment requirements.
13
+ // This can reduce memory consumption by preventing otherwise unnecessary
14
+ // padding in arrays of structs containing `Fingerprint`s. An example of this is
15
+ // the query dependency graph, which contains a large array of `DepNode`s. As of
16
+ // this writing, the size of a `DepNode` decreases by ~30% (from 24 bytes to 17)
17
+ // by using a byte array here instead of two `u64`s, which noticeably decreases
18
+ // total memory usage when compiling large crates. However, it has the potential
19
+ // to increase the instruction count slightly if not carefully implemented.
20
+ #[ derive( Eq , Debug , Clone , Copy ) ]
21
+ pub struct Fingerprint ( [ u8 ; 16 ] ) ;
11
22
12
23
impl Fingerprint {
13
- pub const ZERO : Fingerprint = Fingerprint ( 0 , 0 ) ;
24
+ pub const ZERO : Fingerprint = Fingerprint ( [ 0 ; 16 ] ) ;
14
25
15
26
#[ inline]
16
- pub fn from_smaller_hash ( hash : u64 ) -> Fingerprint {
17
- Fingerprint ( hash, hash)
27
+ fn from_value ( v0 : u64 , v1 : u64 ) -> Fingerprint {
28
+ Fingerprint ( [
29
+ ( v0 >> 0 ) as u8 ,
30
+ ( v0 >> 8 ) as u8 ,
31
+ ( v0 >> 16 ) as u8 ,
32
+ ( v0 >> 24 ) as u8 ,
33
+ ( v0 >> 32 ) as u8 ,
34
+ ( v0 >> 40 ) as u8 ,
35
+ ( v0 >> 48 ) as u8 ,
36
+ ( v0 >> 56 ) as u8 ,
37
+ ( v1 >> 0 ) as u8 ,
38
+ ( v1 >> 8 ) as u8 ,
39
+ ( v1 >> 16 ) as u8 ,
40
+ ( v1 >> 24 ) as u8 ,
41
+ ( v1 >> 32 ) as u8 ,
42
+ ( v1 >> 40 ) as u8 ,
43
+ ( v1 >> 48 ) as u8 ,
44
+ ( v1 >> 56 ) as u8 ,
45
+ ] )
18
46
}
19
47
20
48
#[ inline]
21
- pub fn to_smaller_hash ( & self ) -> u64 {
22
- self . 0
49
+ pub fn as_value ( & self ) -> ( u64 , u64 ) {
50
+ (
51
+ ( ( self . 0 [ 0 ] as u64 ) << 0 )
52
+ | ( ( self . 0 [ 1 ] as u64 ) << 8 )
53
+ | ( ( self . 0 [ 2 ] as u64 ) << 16 )
54
+ | ( ( self . 0 [ 3 ] as u64 ) << 24 )
55
+ | ( ( self . 0 [ 4 ] as u64 ) << 32 )
56
+ | ( ( self . 0 [ 5 ] as u64 ) << 40 )
57
+ | ( ( self . 0 [ 6 ] as u64 ) << 48 )
58
+ | ( ( self . 0 [ 7 ] as u64 ) << 56 ) ,
59
+ ( ( self . 0 [ 8 ] as u64 ) << 0 )
60
+ | ( ( self . 0 [ 9 ] as u64 ) << 8 )
61
+ | ( ( self . 0 [ 10 ] as u64 ) << 16 )
62
+ | ( ( self . 0 [ 11 ] as u64 ) << 24 )
63
+ | ( ( self . 0 [ 12 ] as u64 ) << 32 )
64
+ | ( ( self . 0 [ 13 ] as u64 ) << 40 )
65
+ | ( ( self . 0 [ 14 ] as u64 ) << 48 )
66
+ | ( ( self . 0 [ 15 ] as u64 ) << 56 ) ,
67
+ )
23
68
}
24
69
25
70
#[ inline]
26
- pub fn as_value ( & self ) -> ( u64 , u64 ) {
27
- ( self . 0 , self . 1 )
71
+ fn from_value_u128 ( v : u128 ) -> Fingerprint {
72
+ Fingerprint :: from_value ( v as u64 , ( v >> 64 ) as u64 )
73
+ }
74
+
75
+ #[ inline]
76
+ pub fn as_value_u128 ( & self ) -> u128 {
77
+ let ( v0, v1) = self . as_value ( ) ;
78
+ v0 as u128 | ( ( v1 as u128 ) << 64 )
79
+ }
80
+
81
+ #[ inline]
82
+ pub fn from_smaller_hash ( hash : u64 ) -> Fingerprint {
83
+ Fingerprint :: from_value ( hash, hash)
84
+ }
85
+
86
+ #[ inline]
87
+ pub fn to_smaller_hash ( & self ) -> u64 {
88
+ self . as_value ( ) . 0
28
89
}
29
90
30
91
#[ inline]
31
92
pub fn combine ( self , other : Fingerprint ) -> Fingerprint {
32
93
// See https://stackoverflow.com/a/27952689 on why this function is
33
94
// implemented this way.
34
- Fingerprint (
35
- self . 0 . wrapping_mul ( 3 ) . wrapping_add ( other. 0 ) ,
36
- self . 1 . wrapping_mul ( 3 ) . wrapping_add ( other. 1 ) ,
37
- )
95
+ let v = self . as_value_u128 ( ) . wrapping_mul ( 3 ) . wrapping_add ( other. as_value_u128 ( ) ) ;
96
+ Fingerprint :: from_value_u128 ( v)
38
97
}
39
98
40
99
// Combines two hashes in an order independent way. Make sure this is what
41
100
// you want.
42
101
#[ inline]
43
102
pub fn combine_commutative ( self , other : Fingerprint ) -> Fingerprint {
44
- let a = u128:: from ( self . 1 ) << 64 | u128:: from ( self . 0 ) ;
45
- let b = u128:: from ( other. 1 ) << 64 | u128:: from ( other. 0 ) ;
46
-
47
- let c = a. wrapping_add ( b) ;
48
-
49
- Fingerprint ( ( c >> 64 ) as u64 , c as u64 )
103
+ let v = self . as_value_u128 ( ) . wrapping_add ( other. as_value_u128 ( ) ) ;
104
+ Fingerprint :: from_value_u128 ( v)
50
105
}
51
106
52
107
pub fn to_hex ( & self ) -> String {
53
- format ! ( "{:x}{:x}" , self . 0 , self . 1 )
108
+ let ( self0, self1) = self . as_value ( ) ;
109
+ format ! ( "{:x}{:x}" , self0, self1)
54
110
}
55
111
56
112
pub fn encode_opaque ( & self , encoder : & mut opaque:: Encoder ) -> EncodeResult {
57
- let bytes: [ u8 ; 16 ] = unsafe { mem:: transmute ( [ self . 0 . to_le ( ) , self . 1 . to_le ( ) ] ) } ;
58
-
59
- encoder. emit_raw_bytes ( & bytes) ;
113
+ encoder. emit_raw_bytes ( & self . 0 ) ;
60
114
Ok ( ( ) )
61
115
}
62
116
63
117
pub fn decode_opaque ( decoder : & mut opaque:: Decoder < ' _ > ) -> Result < Fingerprint , String > {
64
- let mut bytes = [ 0 ; 16 ] ;
118
+ let mut fingerprint = Fingerprint :: ZERO ;
119
+ decoder. read_raw_bytes ( & mut fingerprint. 0 ) ?;
120
+ Ok ( fingerprint)
121
+ }
122
+ }
65
123
66
- decoder. read_raw_bytes ( & mut bytes) ?;
124
+ impl std:: fmt:: Display for Fingerprint {
125
+ fn fmt ( & self , formatter : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
126
+ let ( self0, self1) = self . as_value ( ) ;
127
+ write ! ( formatter, "{:x}-{:x}" , self0, self1)
128
+ }
129
+ }
67
130
68
- let [ l, r] : [ u64 ; 2 ] = unsafe { mem:: transmute ( bytes) } ;
131
+ impl Ord for Fingerprint {
132
+ #[ inline]
133
+ fn cmp ( & self , other : & Fingerprint ) -> Ordering {
134
+ // This implementation is faster than the one generated by the `derive` attribute.
135
+ self . as_value_u128 ( ) . cmp ( & other. as_value_u128 ( ) )
136
+ }
137
+ }
69
138
70
- Ok ( Fingerprint ( u64:: from_le ( l) , u64:: from_le ( r) ) )
139
+ impl PartialOrd for Fingerprint {
140
+ #[ inline]
141
+ fn partial_cmp ( & self , other : & Fingerprint ) -> Option < Ordering > {
142
+ // This implementation is faster than the one generated by the `derive` attribute.
143
+ Some ( self . cmp ( other) )
71
144
}
72
145
}
73
146
74
- impl std:: fmt:: Display for Fingerprint {
75
- fn fmt ( & self , formatter : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
76
- write ! ( formatter, "{:x}-{:x}" , self . 0 , self . 1 )
147
+ impl PartialEq for Fingerprint {
148
+ #[ inline]
149
+ fn eq ( & self , other : & Fingerprint ) -> bool {
150
+ // This implementation is faster than the one generated by the `derive` attribute.
151
+ self . as_value_u128 ( ) == other. as_value_u128 ( )
77
152
}
78
153
}
79
154
@@ -91,24 +166,27 @@ trait FingerprintHasher {
91
166
impl < H : Hasher > FingerprintHasher for H {
92
167
#[ inline]
93
168
default fn write_fingerprint ( & mut self , fingerprint : & Fingerprint ) {
94
- self . write_u64 ( fingerprint. 0 ) ;
95
- self . write_u64 ( fingerprint. 1 ) ;
169
+ // It's faster to hash this as two `u64`s than as a `u128` or slice.
170
+ let ( fingerprint0, fingerprint1) = fingerprint. as_value ( ) ;
171
+ self . write_u64 ( fingerprint0) ;
172
+ self . write_u64 ( fingerprint1) ;
96
173
}
97
174
}
98
175
99
176
impl FingerprintHasher for crate :: unhash:: Unhasher {
100
177
#[ inline]
101
178
fn write_fingerprint ( & mut self , fingerprint : & Fingerprint ) {
102
179
// `Unhasher` only wants a single `u64`
103
- self . write_u64 ( fingerprint. 0 ) ;
180
+ let ( fingerprint0, _) = fingerprint. as_value ( ) ;
181
+ self . write_u64 ( fingerprint0) ;
104
182
}
105
183
}
106
184
107
185
impl stable_hasher:: StableHasherResult for Fingerprint {
108
186
#[ inline]
109
187
fn finish ( hasher : stable_hasher:: StableHasher ) -> Self {
110
188
let ( _0, _1) = hasher. finalize ( ) ;
111
- Fingerprint ( _0, _1)
189
+ Fingerprint :: from_value ( _0, _1)
112
190
}
113
191
}
114
192
0 commit comments