@@ -15,7 +15,6 @@ use core::hash;
15
15
use core:: marker:: PhantomData ;
16
16
use core:: mem;
17
17
use core:: ptr;
18
- use core:: slice;
19
18
20
19
/// A 128-bit (2x64) hash output
21
20
#[ derive( Debug , Clone , Copy , Default ) ]
@@ -114,7 +113,7 @@ macro_rules! compress {
114
113
} } ;
115
114
}
116
115
117
- /// Load an integer of the desired type from a byte stream, in LE order. Uses
116
+ /// Loads an integer of the desired type from a byte stream, in LE order. Uses
118
117
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
119
118
/// to load it from a possibly unaligned address.
120
119
///
@@ -132,7 +131,9 @@ macro_rules! load_int_le {
132
131
} } ;
133
132
}
134
133
135
- /// Load an u64 using up to 7 bytes of a byte slice.
134
+ /// Loads a u64 using up to 7 bytes of a byte slice. It looks clumsy but the
135
+ /// `copy_nonoverlapping` calls that occur (via `load_int_le!`) all have fixed
136
+ /// sizes and avoid calling `memcpy`, which is good for speed.
136
137
///
137
138
/// Unsafe because: unchecked indexing at start..start+len
138
139
#[ inline]
@@ -277,35 +278,41 @@ impl<S: Sip> Hasher<S> {
277
278
self . ntail = 0 ;
278
279
}
279
280
280
- // Specialized write function that is only valid for buffers with len <= 8.
281
- // It's used to force inlining of write_u8 and write_usize, those would normally be inlined
282
- // except for composite types (that includes slices and str hashing because of delimiter).
283
- // Without this extra push the compiler is very reluctant to inline delimiter writes,
284
- // degrading performance substantially for the most common use cases.
285
- #[ inline( always) ]
286
- fn short_write ( & mut self , msg : & [ u8 ] ) {
287
- debug_assert ! ( msg. len( ) <= 8 ) ;
288
- let length = msg. len ( ) ;
289
- self . length += length;
281
+ // A specialized write function for values with size <= 8.
282
+ //
283
+ // The hashing of multi-byte integers depends on endianness. E.g.:
284
+ // - little-endian: `write_u32(0xDDCCBBAA)` == `write([0xAA, 0xBB, 0xCC, 0xDD])`
285
+ // - big-endian: `write_u32(0xDDCCBBAA)` == `write([0xDD, 0xCC, 0xBB, 0xAA])`
286
+ //
287
+ // This function does the right thing for little-endian hardware. On
288
+ // big-endian hardware `x` must be byte-swapped first to give the right
289
+ // behaviour. After any byte-swapping, the input must be zero-extended to
290
+ // 64-bits. The caller is responsible for the byte-swapping and
291
+ // zero-extension.
292
+ #[ inline]
293
+ fn short_write < T > ( & mut self , _x : T , x : u64 ) {
294
+ let size = mem:: size_of :: < T > ( ) ;
295
+ self . length += size;
290
296
297
+ // The original number must be zero-extended, not sign-extended.
298
+ debug_assert ! ( if size < 8 { x >> ( 8 * size) == 0 } else { true } ) ;
299
+
300
+ // The number of bytes needed to fill `self.tail`.
291
301
let needed = 8 - self . ntail ;
292
- let fill = cmp:: min ( length, needed) ;
293
- if fill == 8 {
294
- self . tail = unsafe { load_int_le ! ( msg, 0 , u64 ) } ;
295
- } else {
296
- self . tail |= unsafe { u8to64_le ( msg, 0 , fill) } << ( 8 * self . ntail ) ;
297
- if length < needed {
298
- self . ntail += length;
299
- return ;
300
- }
302
+
303
+ self . tail |= x << ( 8 * self . ntail ) ;
304
+ if size < needed {
305
+ self . ntail += size;
306
+ return ;
301
307
}
308
+
309
+ // `self.tail` is full, process it.
302
310
self . state . v3 ^= self . tail ;
303
311
S :: c_rounds ( & mut self . state ) ;
304
312
self . state . v0 ^= self . tail ;
305
313
306
- // Buffered tail is now flushed, process new input.
307
- self . ntail = length - needed;
308
- self . tail = unsafe { u8to64_le ( msg, needed, self . ntail ) } ;
314
+ self . ntail = size - needed;
315
+ self . tail = if needed < 8 { x >> ( 8 * needed) } else { 0 } ;
309
316
}
310
317
}
311
318
@@ -369,19 +376,24 @@ impl hash::Hasher for SipHasher24 {
369
376
}
370
377
371
378
impl < S : Sip > hash:: Hasher for Hasher < S > {
372
- // see short_write comment for explanation
373
379
#[ inline]
374
380
fn write_usize ( & mut self , i : usize ) {
375
- let bytes = unsafe {
376
- slice:: from_raw_parts ( & i as * const usize as * const u8 , mem:: size_of :: < usize > ( ) )
377
- } ;
378
- self . short_write ( bytes) ;
381
+ self . short_write ( i, i. to_le ( ) as u64 ) ;
379
382
}
380
383
381
- // see short_write comment for explanation
382
384
#[ inline]
383
385
fn write_u8 ( & mut self , i : u8 ) {
384
- self . short_write ( & [ i] ) ;
386
+ self . short_write ( i, i as u64 ) ;
387
+ }
388
+
389
+ #[ inline]
390
+ fn write_u32 ( & mut self , i : u32 ) {
391
+ self . short_write ( i, i. to_le ( ) as u64 ) ;
392
+ }
393
+
394
+ #[ inline]
395
+ fn write_u64 ( & mut self , i : u64 ) {
396
+ self . short_write ( i, i. to_le ( ) as u64 ) ;
385
397
}
386
398
387
399
#[ inline]
0 commit comments