@@ -209,10 +209,144 @@ impl<S: Sip> Hasher<S> {
209209 self . state . v3 = self . k1 ^ 0x7465646279746573 ;
210210 self . ntail = 0 ;
211211 }
212+
213+ // A specialized write function for values with size <= 8.
214+ //
215+ // The hashing of multi-byte integers depends on endianness. E.g.:
216+ // - little-endian: `write_u32(0xDDCCBBAA)` == `write([0xAA, 0xBB, 0xCC, 0xDD])`
217+ // - big-endian: `write_u32(0xDDCCBBAA)` == `write([0xDD, 0xCC, 0xBB, 0xAA])`
218+ //
219+ // This function does the right thing for little-endian hardware. On
220+ // big-endian hardware `x` must be byte-swapped first to give the right
221+ // behaviour. After any byte-swapping, the input must be zero-extended to
222+ // 64-bits. The caller is responsible for the byte-swapping and
223+ // zero-extension.
224+ #[ inline]
225+ fn short_write < T > ( & mut self , _x : T , x : u64 ) {
226+ let size = mem:: size_of :: < T > ( ) ;
227+ self . length += size;
228+
229+ // The original number must be zero-extended, not sign-extended.
230+ debug_assert ! ( if size < 8 { x >> ( 8 * size) == 0 } else { true } ) ;
231+
232+ // The number of bytes needed to fill `self.tail`.
233+
234+ let needed = 8 - self . ntail ;
235+
236+ // SipHash parses the input stream as 8-byte little-endian integers.
237+ // Inputs are put into `self.tail` until 8 bytes of data have been
238+ // collected, and then that word is processed.
239+ //
240+ // For example, imagine that `self.tail` is 0x0000_00EE_DDCC_BBAA,
241+ // `self.ntail` is 5 (because 5 bytes have been put into `self.tail`),
242+ // and `needed` is therefore 3.
243+ //
244+ // - Scenario 1, `self.write_u8(0xFF)`: we have already zero-extended
245+ // the input to 0x0000_0000_0000_00FF. We now left-shift it five
246+ // bytes, giving 0x0000_FF00_0000_0000. We then bitwise-OR that value
247+ // into `self.tail`, resulting in 0x0000_FFEE_DDCC_BBAA.
248+ // (Zero-extension of the original input is critical in this scenario
249+ // because we don't want the high two bytes of `self.tail` to be
250+ // touched by the bitwise-OR.) `self.tail` is not yet full, so we
251+ // return early, after updating `self.ntail` to 6.
252+ //
253+ // - Scenario 2, `self.write_u32(0xIIHH_GGFF)`: we have already
254+ // zero-extended the input to 0x0000_0000_IIHH_GGFF. We now
255+ // left-shift it five bytes, giving 0xHHGG_FF00_0000_0000. We then
256+ // bitwise-OR that value into `self.tail`, resulting in
257+ // 0xHHGG_FFEE_DDCC_BBAA. `self.tail` is now full, and we can use it
258+ // to update `self.state`. (As mentioned above, this assumes a
259+ // little-endian machine; on a big-endian machine we would have
260+ // byte-swapped 0xIIHH_GGFF in the caller, giving 0xFFGG_HHII, and we
261+ // would then end up bitwise-ORing 0xGGHH_II00_0000_0000 into
262+ // `self.tail`).
263+ //
264+ self . tail |= x << ( 8 * self . ntail ) ;
265+ if size < needed {
266+ self . ntail += size;
267+ return ;
268+ }
269+
270+ // `self.tail` is full, process it.
271+
272+ self . state . v3 ^= self . tail ;
273+ S :: c_rounds ( & mut self . state ) ;
274+ self . state . v0 ^= self . tail ;
275+
276+ // Continuing scenario 2: we have one byte left over from the input. We
277+ // set `self.ntail` to 1 and `self.tail` to `0x0000_0000_IIHH_GGFF >>
278+ // 8*3`, which is 0x0000_0000_0000_00II. (Or on a big-endian machine
279+ // the prior byte-swapping would leave us with 0x0000_0000_0000_00FF.)
280+ //
281+ // The `if` is needed to avoid shifting by 64 bits, which Rust
282+ // complains about.
283+ self . ntail = size - needed;
284+ self . tail = if needed < 8 { x >> ( 8 * needed) } else { 0 } ;
285+ }
212286}
213287
214288#[ stable( feature = "rust1" , since = "1.0.0" ) ]
215289impl super :: Hasher for SipHasher {
290+ #[ inline]
291+ fn write_u8 ( & mut self , i : u8 ) {
292+ self . 0 . hasher . write_u8 ( i) ;
293+ }
294+
295+ #[ inline]
296+ fn write_u16 ( & mut self , i : u16 ) {
297+ self . 0 . hasher . write_u16 ( i) ;
298+ }
299+
300+ #[ inline]
301+ fn write_u32 ( & mut self , i : u32 ) {
302+ self . 0 . hasher . write_u32 ( i) ;
303+ }
304+
305+ #[ inline]
306+ fn write_u64 ( & mut self , i : u64 ) {
307+ self . 0 . hasher . write_u64 ( i) ;
308+ }
309+
310+ #[ inline]
311+ fn write_u128 ( & mut self , i : u128 ) {
312+ self . 0 . hasher . write_u128 ( i) ;
313+ }
314+
315+ #[ inline]
316+ fn write_usize ( & mut self , i : usize ) {
317+ self . 0 . hasher . write_usize ( i) ;
318+ }
319+
320+ #[ inline]
321+ fn write_i8 ( & mut self , i : i8 ) {
322+ self . 0 . hasher . write_i8 ( i) ;
323+ }
324+
325+ #[ inline]
326+ fn write_i16 ( & mut self , i : i16 ) {
327+ self . 0 . hasher . write_i16 ( i) ;
328+ }
329+
330+ #[ inline]
331+ fn write_i32 ( & mut self , i : i32 ) {
332+ self . 0 . hasher . write_i32 ( i) ;
333+ }
334+
335+ #[ inline]
336+ fn write_i64 ( & mut self , i : i64 ) {
337+ self . 0 . hasher . write_i64 ( i) ;
338+ }
339+
340+ #[ inline]
341+ fn write_i128 ( & mut self , i : i128 ) {
342+ self . 0 . hasher . write_i128 ( i) ;
343+ }
344+
345+ #[ inline]
346+ fn write_isize ( & mut self , i : isize ) {
347+ self . 0 . hasher . write_isize ( i) ;
348+ }
349+
216350 #[ inline]
217351 fn write ( & mut self , msg : & [ u8 ] ) {
218352 self . 0 . hasher . write ( msg)
@@ -231,6 +365,66 @@ impl super::Hasher for SipHasher {
231365
232366#[ unstable( feature = "hashmap_internals" , issue = "none" ) ]
233367impl super :: Hasher for SipHasher13 {
368+ #[ inline]
369+ fn write_u8 ( & mut self , i : u8 ) {
370+ self . hasher . write_u8 ( i) ;
371+ }
372+
373+ #[ inline]
374+ fn write_u16 ( & mut self , i : u16 ) {
375+ self . hasher . write_u16 ( i) ;
376+ }
377+
378+ #[ inline]
379+ fn write_u32 ( & mut self , i : u32 ) {
380+ self . hasher . write_u32 ( i) ;
381+ }
382+
383+ #[ inline]
384+ fn write_u64 ( & mut self , i : u64 ) {
385+ self . hasher . write_u64 ( i) ;
386+ }
387+
388+ #[ inline]
389+ fn write_u128 ( & mut self , i : u128 ) {
390+ self . hasher . write_u128 ( i) ;
391+ }
392+
393+ #[ inline]
394+ fn write_usize ( & mut self , i : usize ) {
395+ self . hasher . write_usize ( i) ;
396+ }
397+
398+ #[ inline]
399+ fn write_i8 ( & mut self , i : i8 ) {
400+ self . hasher . write_i8 ( i) ;
401+ }
402+
403+ #[ inline]
404+ fn write_i16 ( & mut self , i : i16 ) {
405+ self . hasher . write_i16 ( i) ;
406+ }
407+
408+ #[ inline]
409+ fn write_i32 ( & mut self , i : i32 ) {
410+ self . hasher . write_i32 ( i) ;
411+ }
412+
413+ #[ inline]
414+ fn write_i64 ( & mut self , i : i64 ) {
415+ self . hasher . write_i64 ( i) ;
416+ }
417+
418+ #[ inline]
419+ fn write_i128 ( & mut self , i : i128 ) {
420+ self . hasher . write_i128 ( i) ;
421+ }
422+
423+ #[ inline]
424+ fn write_isize ( & mut self , i : isize ) {
425+ self . hasher . write_isize ( i) ;
426+ }
427+
234428 #[ inline]
235429 fn write ( & mut self , msg : & [ u8 ] ) {
236430 self . hasher . write ( msg)
@@ -248,13 +442,59 @@ impl super::Hasher for SipHasher13 {
248442}
249443
250444impl < S : Sip > super :: Hasher for Hasher < S > {
251- // Note: no integer hashing methods (`write_u*`, `write_i*`) are defined
252- // for this type. We could add them, copy the `short_write` implementation
253- // in librustc_data_structures/sip128.rs, and add `write_u*`/`write_i*`
254- // methods to `SipHasher`, `SipHasher13`, and `DefaultHasher`. This would
255- // greatly speed up integer hashing by those hashers, at the cost of
256- // slightly slowing down compile speeds on some benchmarks. See #69152 for
257- // details.
445+ #[ inline]
446+ fn write_u8 ( & mut self , i : u8 ) {
447+ self . short_write ( i, i as u64 ) ;
448+ }
449+
450+ #[ inline]
451+ fn write_u16 ( & mut self , i : u16 ) {
452+ self . short_write ( i, i. to_le ( ) as u64 ) ;
453+ }
454+
455+ #[ inline]
456+ fn write_u32 ( & mut self , i : u32 ) {
457+ self . short_write ( i, i. to_le ( ) as u64 ) ;
458+ }
459+
460+ #[ inline]
461+ fn write_u64 ( & mut self , i : u64 ) {
462+ self . short_write ( i, i. to_le ( ) as u64 ) ;
463+ }
464+
465+ // `write_u128` is currently unimplemented.
466+
467+ #[ inline]
468+ fn write_usize ( & mut self , i : usize ) {
469+ self . short_write ( i, i. to_le ( ) as u64 ) ;
470+ }
471+
472+ fn write_i8 ( & mut self , i : i8 ) {
473+ self . short_write ( i, i as u8 as u64 ) ;
474+ }
475+
476+ #[ inline]
477+ fn write_i16 ( & mut self , i : i16 ) {
478+ self . short_write ( i, ( i as u16 ) . to_le ( ) as u64 ) ;
479+ }
480+
481+ #[ inline]
482+ fn write_i32 ( & mut self , i : i32 ) {
483+ self . short_write ( i, ( i as u32 ) . to_le ( ) as u64 ) ;
484+ }
485+
486+ #[ inline]
487+ fn write_i64 ( & mut self , i : i64 ) {
488+ self . short_write ( i, ( i as u64 ) . to_le ( ) as u64 ) ;
489+ }
490+
491+ // `write_i128` is currently unimplemented.
492+
493+ #[ inline]
494+ fn write_isize ( & mut self , i : isize ) {
495+ self . short_write ( i, ( i as usize ) . to_le ( ) as u64 ) ;
496+ }
497+
258498 #[ inline]
259499 fn write ( & mut self , msg : & [ u8 ] ) {
260500 let length = msg. len ( ) ;
0 commit comments