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