3
3
4
4
using System ;
5
5
using System . Diagnostics ;
6
- using System . Linq ;
7
6
using System . Numerics ;
8
7
9
8
namespace Microsoft . AspNet . Server . Kestrel . Infrastructure
10
9
{
11
10
public struct MemoryPoolIterator2
12
11
{
13
- /// <summary>
14
- /// Array of "minus one" bytes of the length of SIMD operations on the current hardware. Used as an argument in the
15
- /// vector dot product that counts matching character occurrence.
16
- /// </summary>
17
- private static Vector < byte > _dotCount = new Vector < byte > ( Byte . MaxValue ) ;
18
-
19
- /// <summary>
20
- /// Array of negative numbers starting at 0 and continuing for the length of SIMD operations on the current hardware.
21
- /// Used as an argument in the vector dot product that determines matching character index.
22
- /// </summary>
23
- private static Vector < byte > _dotIndex = new Vector < byte > ( Enumerable . Range ( 0 , Vector < byte > . Count ) . Select ( x => ( byte ) - x ) . ToArray ( ) ) ;
24
-
25
12
private MemoryPoolBlock2 _block ;
26
13
private int _index ;
27
14
@@ -189,7 +176,6 @@ public int Seek(int char0)
189
176
}
190
177
191
178
var byte0 = ( byte ) char0 ;
192
- var vectorStride = Vector< byte > . Count ;
193
179
var ch0Vector = new Vector < byte > ( byte0 ) ;
194
180
195
181
var block = _block;
@@ -212,27 +198,20 @@ public int Seek(int char0)
212
198
while ( block . End != index )
213
199
{
214
200
var following = block. End - index ;
215
- if ( following >= vectorStride )
201
+ if ( following >= Vector < byte > . Count )
216
202
{
217
203
var data = new Vector < byte > ( array , index ) ;
218
204
var ch0Equals = Vector. Equals( data , ch0Vector ) ;
219
- var ch0Count = Vector . Dot ( ch0Equals , _dotCount ) ;
220
205
221
- if ( ch0Count = = 0 )
206
+ if ( ch0Equals . Equals ( Vector < byte > . Zero ) )
222
207
{
223
- index += vectorStride ;
208
+ index += Vector < byte > . Count ;
224
209
continue ;
225
210
}
226
- else if ( ch0Count = = 1 )
227
- {
228
- _block = block ;
229
- _index = index + Vector . Dot ( ch0Equals , _dotIndex ) ;
230
- return char0;
231
- }
232
- else
233
- {
234
- following = vectorStride ;
235
- }
211
+
212
+ _block = block ;
213
+ _index = index + FindFirstEqualByte ( ch0Equals ) ;
214
+ return char0;
236
215
}
237
216
while ( following > 0 )
238
217
{
@@ -258,7 +237,6 @@ public int Seek(int char0, int char1)
258
237
259
238
var byte0 = ( byte ) char0 ;
260
239
var byte1 = ( byte ) char1 ;
261
- var vectorStride = Vector < byte > . Count ;
262
240
var ch0Vector = new Vector < byte > ( byte0 ) ;
263
241
var ch1Vector = new Vector < byte > ( byte1 ) ;
264
242
@@ -282,40 +260,39 @@ public int Seek(int char0, int char1)
282
260
while ( block . End != index )
283
261
{
284
262
var following = block. End - index ;
285
- if ( following >= vectorStride )
263
+ if ( following >= Vector < byte > . Count )
286
264
{
287
265
var data = new Vector < byte > ( array , index ) ;
288
266
var ch0Equals = Vector. Equals( data , ch0Vector ) ;
289
- var ch0Count = Vector . Dot ( ch0Equals , _dotCount ) ;
290
267
var ch1Equals = Vector . Equals ( data , ch1Vector ) ;
291
- var ch1Count = Vector . Dot ( ch1Equals , _dotCount ) ;
268
+ int ch0Index = int . MaxValue ;
269
+ int ch1Index = int . MaxValue ;
292
270
293
- if ( ch0Count = = 0 && ch1Count == 0 )
271
+ if ( ! ch0Equals . Equals ( Vector < byte > . Zero ) )
294
272
{
295
- index += vectorStride ;
296
- continue ;
273
+ ch0Index = FindFirstEqualByte ( ch0Equals ) ;
297
274
}
298
- else if ( ch0Count < 2 && ch1Count < 2 )
275
+ if ( ! ch1Equals . Equals ( Vector < byte > . Zero ) )
299
276
{
300
- var ch0Index = ch0Count == 1 ? Vector . Dot ( ch0Equals , _dotIndex ) : byte . MaxValue ;
301
- var ch1Index = ch1Count == 1 ? Vector . Dot ( ch1Equals , _dotIndex ) : byte . MaxValue ;
302
- if ( ch0Index < ch1Index )
303
- {
304
- _block = block ;
305
- _index = index + ch0Index ;
306
- return char0;
307
- }
308
- else
309
- {
310
- _block = block ;
311
- _index = index + ch1Index ;
312
- return char1;
313
- }
277
+ ch1Index = FindFirstEqualByte ( ch1Equals ) ;
314
278
}
315
- else
279
+
280
+ if ( ch0Index == int . MaxValue && ch1Index == int . MaxValue )
281
+ {
282
+ index += Vector < byte > . Count ;
283
+ continue ;
284
+ }
285
+
286
+ _block = block ;
287
+
288
+ if ( ch0Index < ch1Index )
316
289
{
317
- following = vectorStride;
290
+ _index = index + ch0Index ;
291
+ return char0;
318
292
}
293
+
294
+ _index = index + ch1Index ;
295
+ return char1;
319
296
}
320
297
while ( following > 0 )
321
298
{
@@ -349,7 +326,6 @@ public int Seek(int char0, int char1, int char2)
349
326
var byte0 = ( byte ) char0 ;
350
327
var byte1 = ( byte ) char1 ;
351
328
var byte2 = ( byte ) char2 ;
352
- var vectorStride = Vector< byte > . Count ;
353
329
var ch0Vector = new Vector < byte > ( byte0 ) ;
354
330
var ch1Vector = new Vector < byte > ( byte1 ) ;
355
331
var ch2Vector = new Vector < byte > ( byte2 ) ;
@@ -374,64 +350,68 @@ public int Seek(int char0, int char1, int char2)
374
350
while ( block . End != index )
375
351
{
376
352
var following = block. End - index ;
377
- if ( following >= vectorStride )
353
+ if ( following >= Vector < byte > . Count )
378
354
{
379
355
var data = new Vector < byte > ( array , index ) ;
380
356
var ch0Equals = Vector. Equals( data , ch0Vector ) ;
381
- var ch0Count = Vector . Dot ( ch0Equals , _dotCount ) ;
382
357
var ch1Equals = Vector . Equals ( data , ch1Vector ) ;
383
- var ch1Count = Vector . Dot ( ch1Equals , _dotCount ) ;
384
358
var ch2Equals = Vector . Equals ( data , ch2Vector ) ;
385
- var ch2Count = Vector . Dot ( ch2Equals , _dotCount ) ;
359
+ int ch0Index = int . MaxValue ;
360
+ int ch1Index = int . MaxValue ;
361
+ int ch2Index = int . MaxValue ;
386
362
387
- if ( ch0Count = = 0 && ch1Count == 0 && ch2Count == 0 )
363
+ if ( ! ch0Equals . Equals ( Vector < byte > . Zero ) )
388
364
{
389
- index += vectorStride ;
390
- continue ;
365
+ ch0Index = FindFirstEqualByte ( ch0Equals ) ;
366
+ }
367
+ if ( ! ch1Equals . Equals ( Vector < byte > . Zero ) )
368
+ {
369
+ ch1Index = FindFirstEqualByte ( ch1Equals ) ;
391
370
}
392
- else if ( ch0Count < 2 && ch1Count < 2 && ch2Count < 2 )
371
+ if ( ! ch2Equals . Equals ( Vector < byte > . Zero ) )
393
372
{
394
- var ch0Index = ch0Count == 1 ? Vector . Dot ( ch0Equals , _dotIndex ) : byte . MaxValue ;
395
- var ch1Index = ch1Count == 1 ? Vector . Dot ( ch1Equals , _dotIndex ) : byte . MaxValue ;
396
- var ch2Index = ch2Count == 1 ? Vector . Dot ( ch2Equals , _dotIndex ) : byte . MaxValue ;
373
+ ch2Index = FindFirstEqualByte ( ch2Equals ) ;
374
+ }
397
375
398
- int toReturn , toMove;
399
- if ( ch0Index < ch1Index )
376
+ if ( ch0Index == int . MaxValue && ch1Index == int . MaxValue && ch2Index == int . MaxValue )
377
+ {
378
+ index += Vector < byte > . Count ;
379
+ continue ;
380
+ }
381
+
382
+ int toReturn , toMove ;
383
+ if ( ch0Index < ch1Index )
384
+ {
385
+ if ( ch0Index < ch2Index )
400
386
{
401
- if ( ch0Index < ch2Index )
402
- {
403
- toReturn = char0 ;
404
- toMove = ch0Index ;
405
- }
406
- else
407
- {
408
- toReturn = char2 ;
409
- toMove = ch2Index ;
410
- }
387
+ toReturn = char0 ;
388
+ toMove = ch0Index ;
411
389
}
412
390
else
413
391
{
414
- if ( ch1Index < ch2Index )
415
- {
416
- toReturn = char1;
417
- toMove = ch1Index;
418
- }
419
- else
420
- {
421
- toReturn = char2;
422
- toMove = ch2Index;
423
- }
392
+ toReturn = char2 ;
393
+ toMove = ch2Index ;
424
394
}
425
-
426
- _block = block;
427
- _index = index + toMove ;
428
- return toReturn;
429
395
}
430
396
else
431
397
{
432
- following = vectorStride ;
398
+ if ( ch1Index < ch2Index )
399
+ {
400
+ toReturn = char1;
401
+ toMove = ch1Index;
402
+ }
403
+ else
404
+ {
405
+ toReturn = char2;
406
+ toMove = ch2Index;
407
+ }
433
408
}
409
+
410
+ _block = block;
411
+ _index = index + toMove ;
412
+ return toReturn;
434
413
}
414
+
435
415
while ( following > 0 )
436
416
{
437
417
var byteIndex = block. Array [ index ] ;
@@ -460,6 +440,34 @@ public int Seek(int char0, int char1, int char2)
460
440
}
461
441
}
462
442
443
+ private static int FindFirstEqualByte( Vector < byte > chEquals )
444
+ {
445
+ // Quasi-tree search
446
+ var vector64 = Vector. AsVectorInt64 ( chEquals ) ;
447
+ for ( var i = 0 ; i < Vector < long > . Count ; i++ )
448
+ {
449
+ var longValue = vector64[ i] ;
450
+ if ( longValue == 0 ) continue ;
451
+
452
+ var shift = i << 1 ;
453
+ var offset = shift << 2 ;
454
+ var vector32 = Vector. AsVectorInt32( chEquals) ;
455
+ if ( vector32[ shift] != 0 )
456
+ {
457
+ if ( chEquals[ offset] != 0 ) return offset;
458
+ if ( chEquals[ ++ offset] != 0 ) return offset;
459
+ if ( chEquals[ ++ offset] != 0 ) return offset;
460
+ return ++ offset;
461
+ }
462
+ offset += 4 ;
463
+ if ( chEquals[ offset] != 0 ) return offset;
464
+ if ( chEquals[ ++ offset] != 0 ) return offset;
465
+ if ( chEquals[ ++ offset] != 0 ) return offset;
466
+ return ++ offset;
467
+ }
468
+ throw new InvalidOperationException( ) ;
469
+ }
470
+
463
471
/// <summary>
464
472
/// Save the data at the current location then move to the next available space.
465
473
/// </summary>
0 commit comments