@@ -1459,6 +1459,52 @@ static unsafe bool IsMboxMarker (byte[] text, bool allowMunged = false)
1459
1459
}
1460
1460
}
1461
1461
1462
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
1463
+ static unsafe byte * EndOfLine ( byte * inptr , byte * inend )
1464
+ {
1465
+ #if NETCOREAPP
1466
+ var span = new ReadOnlySpan < byte > ( inptr , ( int ) ( inend - inptr ) ) ;
1467
+
1468
+ return inptr += span . IndexOf ( ( byte ) '\n ' ) ;
1469
+ #else
1470
+ // scan for a linefeed character until we are 4-byte aligned.
1471
+ switch ( ( ( long ) inptr ) & 0x03 ) {
1472
+ case 1 :
1473
+ if ( * inptr == ( byte ) '\n ' )
1474
+ break ;
1475
+ inptr ++ ;
1476
+ goto case 2 ;
1477
+ case 2 :
1478
+ if ( * inptr == ( byte ) '\n ' )
1479
+ break ;
1480
+ inptr ++ ;
1481
+ goto case 3 ;
1482
+ case 3 :
1483
+ if ( * inptr != ( byte ) '\n ' )
1484
+ inptr ++ ;
1485
+ break ;
1486
+ }
1487
+
1488
+ if ( * inptr != ( byte ) '\n ' ) {
1489
+ // -funroll-loops, yippee ki-yay.
1490
+ do {
1491
+ uint mask = * ( ( uint * ) inptr ) ^ 0x0A0A0A0A ;
1492
+ mask = ( ( mask - 0x01010101 ) & ( ~ mask & 0x80808080 ) ) ;
1493
+
1494
+ if ( mask != 0 )
1495
+ break ;
1496
+
1497
+ inptr += 4 ;
1498
+ } while ( true ) ;
1499
+
1500
+ while ( * inptr != ( byte ) '\n ' )
1501
+ inptr ++ ;
1502
+ }
1503
+
1504
+ return inptr ;
1505
+ #endif
1506
+ }
1507
+
1462
1508
unsafe bool StepMboxMarkerStart ( byte * inbuf , ref bool midline )
1463
1509
{
1464
1510
byte * inptr = inbuf + inputIndex ;
@@ -1468,9 +1514,7 @@ unsafe bool StepMboxMarkerStart (byte* inbuf, ref bool midline)
1468
1514
1469
1515
if ( midline ) {
1470
1516
// we're in the middle of a line, so we need to scan for the end of the line
1471
- // TODO: unroll this loop?
1472
- while ( * inptr != ( byte ) '\n ' )
1473
- inptr ++ ;
1517
+ inptr = EndOfLine ( inptr , inend + 1 ) ;
1474
1518
1475
1519
if ( inptr == inend ) {
1476
1520
// we don't have enough input data
@@ -1492,9 +1536,7 @@ unsafe bool StepMboxMarkerStart (byte* inbuf, ref bool midline)
1492
1536
}
1493
1537
1494
1538
// scan for the end of the line
1495
- // TODO: unroll this loop?
1496
- while ( * inptr != ( byte ) '\n ' )
1497
- inptr ++ ;
1539
+ inptr = EndOfLine ( inptr , inend + 1 ) ;
1498
1540
1499
1541
if ( inptr == inend ) {
1500
1542
// we don't have enough data to check for a From line
@@ -1522,9 +1564,7 @@ unsafe bool StepMboxMarker (byte* inbuf, out int count)
1522
1564
* inend = ( byte ) '\n ' ;
1523
1565
1524
1566
// scan for the end of the line
1525
- // TODO: unroll this loop?
1526
- while ( * inptr != ( byte ) '\n ' )
1527
- inptr ++ ;
1567
+ inptr = EndOfLine ( inptr , inend + 1 ) ;
1528
1568
1529
1569
count = ( int ) ( inptr - start ) ;
1530
1570
@@ -1711,9 +1751,7 @@ unsafe bool StepHeaderValue (byte* inbuf, ref bool midline)
1711
1751
* inend = ( byte ) '\n ' ;
1712
1752
1713
1753
while ( inptr < inend && ( midline || IsBlank ( * inptr ) ) ) {
1714
- // TODO: unroll this loop?
1715
- while ( * inptr != ( byte ) '\n ' )
1716
- inptr ++ ;
1754
+ inptr = EndOfLine ( inptr , inend + 1 ) ;
1717
1755
1718
1756
if ( inptr == inend ) {
1719
1757
// We've reached the end of the input buffer, and we are currently in the middle of a line.
@@ -1775,9 +1813,7 @@ unsafe bool TryCheckBoundaryWithinHeaderBlock (byte* inbuf)
1775
1813
1776
1814
* inend = ( byte ) '\n ' ;
1777
1815
1778
- // TODO: unroll this loop?
1779
- while ( * inptr != ( byte ) '\n ' )
1780
- inptr ++ ;
1816
+ inptr = EndOfLine ( inptr , inend + 1 ) ;
1781
1817
1782
1818
if ( inptr == inend )
1783
1819
return false ;
@@ -2004,8 +2040,7 @@ unsafe bool SkipBoundaryMarkerInternal (byte* inbuf, bool endBoundary)
2004
2040
inptr += currentBoundary . Length ;
2005
2041
2006
2042
// skip over any trailing whitespace
2007
- while ( * inptr != ( byte ) '\n ' )
2008
- inptr ++ ;
2043
+ inptr = EndOfLine ( inptr , inend + 1 ) ;
2009
2044
2010
2045
if ( inptr < inend ) {
2011
2046
inputIndex = ( int ) ( inptr - inbuf ) ;
@@ -2258,41 +2293,7 @@ unsafe bool ScanContent (byte* inbuf, ref bool midline, ref bool[] formats)
2258
2293
while ( inptr < inend ) {
2259
2294
byte * start = inptr;
2260
2295
2261
- // Note: we can always depend on byte[] arrays being 4-byte aligned on 32bit and 64bit architectures
2262
- // so we can safely use the startIndex instead of `((long) inptr) & 3` to determine the alignment.
2263
- switch ( startIndex & 3 ) {
2264
- case 1 :
2265
- if ( * inptr = = ( byte ) '\n ' )
2266
- break;
2267
- inptr ++ ;
2268
- goto case 2 ;
2269
- case 2 :
2270
- if ( * inptr = = ( byte ) '\n ' )
2271
- break;
2272
- inptr ++ ;
2273
- goto case 3 ;
2274
- case 3 :
2275
- if ( * inptr ! = ( byte ) '\n ' )
2276
- inptr++ ;
2277
- break ;
2278
- }
2279
-
2280
- if ( * inptr != ( byte ) '\n ') {
2281
- // -funroll-loops, yippee ki-yay.
2282
- do {
2283
- uint mask = * ( ( uint * ) inptr ) ^ 0x0A0A0A0A ;
2284
- mask = ( ( mask - 0x01010101 ) & ( ~ mask & 0x80808080 ) ) ;
2285
-
2286
- if ( mask != 0 )
2287
- break;
2288
-
2289
- inptr += 4 ;
2290
- } while ( true ) ;
2291
-
2292
- while ( * inptr != ( byte ) '\n ' )
2293
- inptr ++ ;
2294
- }
2295
-
2296
+ inptr = EndOfLine ( inptr , inend + 1 ) ;
2296
2297
length = ( int ) ( inptr - start ) ;
2297
2298
2298
2299
if ( inptr < inend ) {
@@ -2464,9 +2465,7 @@ unsafe int ConstructMessagePart (byte* inbuf, int depth, CancellationToken cance
2464
2465
2465
2466
* inend = ( byte ) '\n ';
2466
2467
2467
- // TODO: unroll this loop?
2468
- while ( * inptr != ( byte ) '\n ' )
2469
- inptr ++ ;
2468
+ inptr = EndOfLine ( inptr, inend + 1 ) ;
2470
2469
2471
2470
// Note: This isn't obvious, but if the "boundary" that was found is an Mbox "From " line, then
2472
2471
// either the current stream offset is >= contentEnd -or- RespectContentLength is false. It will
0 commit comments