11//! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes.
22
3+ // This code is very hot and uses lots of arithmetic, avoid overflow checks for performance.
4+ // See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727
5+ use rustc_serialize:: int_overflow:: { DebugStrictAdd , DebugStrictSub } ;
36use std:: hash:: Hasher ;
47use std:: mem:: { self , MaybeUninit } ;
58use std:: ptr;
@@ -103,19 +106,19 @@ unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize)
103106 }
104107
105108 let mut i = 0 ;
106- if i + 3 < count {
109+ if i. debug_strict_add ( 3 ) < count {
107110 ptr:: copy_nonoverlapping ( src. add ( i) , dst. add ( i) , 4 ) ;
108- i += 4 ;
111+ i = i . debug_strict_add ( 4 ) ;
109112 }
110113
111- if i + 1 < count {
114+ if i. debug_strict_add ( 1 ) < count {
112115 ptr:: copy_nonoverlapping ( src. add ( i) , dst. add ( i) , 2 ) ;
113- i += 2
116+ i = i . debug_strict_add ( 2 )
114117 }
115118
116119 if i < count {
117120 * dst. add ( i) = * src. add ( i) ;
118- i += 1 ;
121+ i = i . debug_strict_add ( 1 ) ;
119122 }
120123
121124 debug_assert_eq ! ( i, count) ;
@@ -211,14 +214,14 @@ impl SipHasher128 {
211214 debug_assert ! ( nbuf < BUFFER_SIZE ) ;
212215 debug_assert ! ( nbuf + LEN < BUFFER_WITH_SPILL_SIZE ) ;
213216
214- if nbuf + LEN < BUFFER_SIZE {
217+ if nbuf. debug_strict_add ( LEN ) < BUFFER_SIZE {
215218 unsafe {
216219 // The memcpy call is optimized away because the size is known.
217220 let dst = ( self . buf . as_mut_ptr ( ) as * mut u8 ) . add ( nbuf) ;
218221 ptr:: copy_nonoverlapping ( bytes. as_ptr ( ) , dst, LEN ) ;
219222 }
220223
221- self . nbuf = nbuf + LEN ;
224+ self . nbuf = nbuf. debug_strict_add ( LEN ) ;
222225
223226 return ;
224227 }
@@ -265,8 +268,9 @@ impl SipHasher128 {
265268 // This function should only be called when the write fills the buffer.
266269 // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
267270 // LEN is statically known, so the branch is optimized away.
268- self . nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE } ;
269- self . processed += BUFFER_SIZE ;
271+ self . nbuf =
272+ if LEN == 1 { 0 } else { nbuf. debug_strict_add ( LEN ) . debug_strict_sub ( BUFFER_SIZE ) } ;
273+ self . processed = self . processed . debug_strict_add ( BUFFER_SIZE ) ;
270274 }
271275 }
272276
@@ -277,7 +281,7 @@ impl SipHasher128 {
277281 let nbuf = self . nbuf ;
278282 debug_assert ! ( nbuf < BUFFER_SIZE ) ;
279283
280- if nbuf + length < BUFFER_SIZE {
284+ if nbuf. debug_strict_add ( length) < BUFFER_SIZE {
281285 unsafe {
282286 let dst = ( self . buf . as_mut_ptr ( ) as * mut u8 ) . add ( nbuf) ;
283287
@@ -289,7 +293,7 @@ impl SipHasher128 {
289293 }
290294 }
291295
292- self . nbuf = nbuf + length;
296+ self . nbuf = nbuf. debug_strict_add ( length) ;
293297
294298 return ;
295299 }
@@ -315,7 +319,7 @@ impl SipHasher128 {
315319 // This function should only be called when the write fills the buffer,
316320 // so we know that there is enough input to fill the current element.
317321 let valid_in_elem = nbuf % ELEM_SIZE ;
318- let needed_in_elem = ELEM_SIZE - valid_in_elem;
322+ let needed_in_elem = ELEM_SIZE . debug_strict_sub ( valid_in_elem) ;
319323
320324 let src = msg. as_ptr ( ) ;
321325 let dst = ( self . buf . as_mut_ptr ( ) as * mut u8 ) . add ( nbuf) ;
@@ -327,7 +331,7 @@ impl SipHasher128 {
327331 // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0.
328332 // We know that is true, because last step ensured we have a full
329333 // element in the buffer.
330- let last = nbuf / ELEM_SIZE + 1 ;
334+ let last = ( nbuf / ELEM_SIZE ) . debug_strict_add ( 1 ) ;
331335
332336 for i in 0 ..last {
333337 let elem = self . buf . get_unchecked ( i) . assume_init ( ) . to_le ( ) ;
@@ -338,7 +342,7 @@ impl SipHasher128 {
338342
339343 // Process the remaining element-sized chunks of input.
340344 let mut processed = needed_in_elem;
341- let input_left = length - processed;
345+ let input_left = length. debug_strict_sub ( processed) ;
342346 let elems_left = input_left / ELEM_SIZE ;
343347 let extra_bytes_left = input_left % ELEM_SIZE ;
344348
@@ -347,7 +351,7 @@ impl SipHasher128 {
347351 self . state . v3 ^= elem;
348352 Sip13Rounds :: c_rounds ( & mut self . state ) ;
349353 self . state . v0 ^= elem;
350- processed += ELEM_SIZE ;
354+ processed = processed . debug_strict_add ( ELEM_SIZE ) ;
351355 }
352356
353357 // Copy remaining input into start of buffer.
@@ -356,7 +360,7 @@ impl SipHasher128 {
356360 copy_nonoverlapping_small ( src, dst, extra_bytes_left) ;
357361
358362 self . nbuf = extra_bytes_left;
359- self . processed += nbuf + processed;
363+ self . processed = self . processed . debug_strict_add ( nbuf. debug_strict_add ( processed) ) ;
360364 }
361365 }
362366
@@ -394,7 +398,7 @@ impl SipHasher128 {
394398 } ;
395399
396400 // Finalize the hash.
397- let length = self . processed + self . nbuf ;
401+ let length = self . processed . debug_strict_add ( self . nbuf ) ;
398402 let b: u64 = ( ( length as u64 & 0xff ) << 56 ) | elem;
399403
400404 state. v3 ^= b;
0 commit comments