@@ -209,10 +209,144 @@ impl<S: Sip> Hasher<S> {
209
209
self . state . v3 = self . k1 ^ 0x7465646279746573 ;
210
210
self . ntail = 0 ;
211
211
}
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
+ }
212
286
}
213
287
214
288
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
215
289
impl 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
+
216
350
#[ inline]
217
351
fn write ( & mut self , msg : & [ u8 ] ) {
218
352
self . 0 . hasher . write ( msg)
@@ -231,6 +365,66 @@ impl super::Hasher for SipHasher {
231
365
232
366
#[ unstable( feature = "hashmap_internals" , issue = "none" ) ]
233
367
impl 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
+
234
428
#[ inline]
235
429
fn write ( & mut self , msg : & [ u8 ] ) {
236
430
self . hasher . write ( msg)
@@ -248,13 +442,59 @@ impl super::Hasher for SipHasher13 {
248
442
}
249
443
250
444
impl < 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
+
258
498
#[ inline]
259
499
fn write ( & mut self , msg : & [ u8 ] ) {
260
500
let length = msg. len ( ) ;
0 commit comments