55using System . Buffers ;
66using System . Buffers . Binary ;
77using System . Runtime . CompilerServices ;
8+ using System . Runtime . InteropServices ;
89using System . Text ;
910using System . Threading ;
1011
@@ -149,17 +150,32 @@ private static void ComputeHash(ReadOnlySpan<byte> data,
149150 out uint hash1 ,
150151 out uint hash2 )
151152 {
152- uint a , b , c ;
153+ uint len = ( uint ) data . Length ;
154+ uint a = 0xDEADBEEF + len + seed1 ;
155+ uint b = a ;
156+ uint c = a + seed2 ;
153157
154- a = b = c = ( uint ) ( 0xdeadbeef + data . Length + seed1 ) ;
155- c += seed2 ;
158+ int tripletCount = data . Length > 12 ? ( data . Length - 1 ) / 12 : 0 ;
156159
157- int index = 0 , size = data . Length ;
158- while ( size > 12 )
160+ int regionBytes = tripletCount * 12 ; // must be divisible by 4
161+ ReadOnlySpan < byte > region = data . Slice ( 0 , regionBytes ) ;
162+ ReadOnlySpan < uint > words = MemoryMarshal . Cast < byte , uint > ( region ) ;
163+
164+ int i = 0 ;
165+ for ( ; i < tripletCount ; i ++ )
159166 {
160- a += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( index ) ) ;
161- b += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( index + 4 ) ) ;
162- c += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( index + 8 ) ) ;
167+ int idx = i * 3 ;
168+ uint w0 = BitConverter . IsLittleEndian ? words [ idx ] : BinaryPrimitives . ReverseEndianness ( words [ idx ] ) ;
169+ uint w1 = BitConverter . IsLittleEndian
170+ ? words [ idx + 1 ]
171+ : BinaryPrimitives . ReverseEndianness ( words [ idx + 1 ] ) ;
172+ uint w2 = BitConverter . IsLittleEndian
173+ ? words [ idx + 2 ]
174+ : BinaryPrimitives . ReverseEndianness ( words [ idx + 2 ] ) ;
175+
176+ a += w0 ;
177+ b += w1 ;
178+ c += w2 ;
163179
164180 a -= c ;
165181 a ^= ( c << 4 ) | ( c >> 28 ) ;
@@ -184,51 +200,50 @@ private static void ComputeHash(ReadOnlySpan<byte> data,
184200 c -= b ;
185201 c ^= ( b << 4 ) | ( b >> 28 ) ;
186202 b += a ;
187-
188- index += 12 ;
189- size -= 12 ;
190203 }
191204
205+ int byteIndex = regionBytes ;
206+ int size = data . Length - byteIndex ;
192207 switch ( size )
193208 {
194209 case 12 :
195- a += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( index ) ) ;
196- b += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( index + 4 ) ) ;
197- c += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( index + 8 ) ) ;
210+ a += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( byteIndex ) ) ;
211+ b += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( byteIndex + 4 ) ) ;
212+ c += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( byteIndex + 8 ) ) ;
198213 break ;
199214 case 11 :
200- c += ( ( uint ) data [ index + 10 ] ) << 16 ;
215+ c += ( uint ) data [ byteIndex + 10 ] << 16 ;
201216 goto case 10 ;
202217 case 10 :
203- c += ( ( uint ) data [ index + 9 ] ) << 8 ;
218+ c += ( uint ) data [ byteIndex + 9 ] << 8 ;
204219 goto case 9 ;
205220 case 9 :
206- c += ( uint ) data [ index + 8 ] ;
221+ c += data [ byteIndex + 8 ] ;
207222 goto case 8 ;
208223 case 8 :
209- b += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( index + 4 ) ) ;
210- a += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( index ) ) ;
224+ b += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( byteIndex + 4 ) ) ;
225+ a += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( byteIndex ) ) ;
211226 break ;
212227 case 7 :
213- b += ( ( uint ) data [ index + 6 ] ) << 16 ;
228+ b += ( uint ) data [ byteIndex + 6 ] << 16 ;
214229 goto case 6 ;
215230 case 6 :
216- b += ( ( uint ) data [ index + 5 ] ) << 8 ;
231+ b += ( uint ) data [ byteIndex + 5 ] << 8 ;
217232 goto case 5 ;
218233 case 5 :
219- b += ( uint ) data [ index + 4 ] ;
234+ b += data [ byteIndex + 4 ] ;
220235 goto case 4 ;
221236 case 4 :
222- a += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( index ) ) ;
237+ a += BinaryPrimitives . ReadUInt32LittleEndian ( data . Slice ( byteIndex ) ) ;
223238 break ;
224239 case 3 :
225- a += ( ( uint ) data [ index + 2 ] ) << 16 ;
240+ a += ( uint ) data [ byteIndex + 2 ] << 16 ;
226241 goto case 2 ;
227242 case 2 :
228- a += ( ( uint ) data [ index + 1 ] ) << 8 ;
243+ a += ( uint ) data [ byteIndex + 1 ] << 8 ;
229244 goto case 1 ;
230245 case 1 :
231- a += ( uint ) data [ index ] ;
246+ a += data [ byteIndex ] ;
232247 break ;
233248 case 0 :
234249 hash1 = c ;
0 commit comments