Skip to content

Commit de1c68b

Browse files
committed
Optimization: Use currentBoundary state to skip over boundary markers
Instead of having MimeReader.SkipLine/Async() loop over the entire line containing what we know is a boundary marker, just skip over the known length of the currentBoundary - this way we only need to loop over the trailing whitespace characters. Also, there's no need to call ReadAhead because we know we already have the full line.
1 parent 6e3afba commit de1c68b

File tree

2 files changed

+19
-28
lines changed

2 files changed

+19
-28
lines changed

MimeKit/AsyncMimeReader.cs

+7-13
Original file line numberDiff line numberDiff line change
@@ -291,19 +291,13 @@ async Task StepHeadersAsync (CancellationToken cancellationToken)
291291
await OnHeadersEndAsync (headerBlockBegin, headersBeginLineNumber, headerBlockEnd, lineNumber, cancellationToken).ConfigureAwait (false);
292292
}
293293

294-
async Task<bool> SkipLineAsync (bool consumeNewLine, CancellationToken cancellationToken)
294+
bool SkipBoundaryMarker (bool endBoundary)
295295
{
296-
do {
297-
unsafe {
298-
fixed (byte* inbuf = input) {
299-
if (InnerSkipLine (inbuf, consumeNewLine))
300-
return true;
301-
}
296+
unsafe {
297+
fixed (byte* inbuf = input) {
298+
return SkipBoundaryMarker (inbuf, endBoundary);
302299
}
303-
304-
if (await ReadAheadAsync (ReadAheadSize, 1, cancellationToken).ConfigureAwait (false) <= 0)
305-
return false;
306-
} while (true);
300+
}
307301
}
308302

309303
async Task<MimeParserState> StepAsync (CancellationToken cancellationToken)
@@ -507,7 +501,7 @@ async Task MultipartScanSubpartsAsync (ContentType multipartContentType, int dep
507501

508502
do {
509503
// skip over the boundary marker
510-
if (!await SkipLineAsync (true, cancellationToken).ConfigureAwait (false)) {
504+
if (!SkipBoundaryMarker (endBoundary: false)) {
511505
await OnMultipartBoundaryAsync (multipartContentType.Boundary, boundaryOffset, GetOffset (inputIndex), lineNumber, cancellationToken).ConfigureAwait (false);
512506
boundary = BoundaryType.Eos;
513507
return;
@@ -609,7 +603,7 @@ async Task<int> ConstructMultipartAsync (ContentType contentType, int depth, Can
609603
var boundaryOffset = GetOffset (inputIndex);
610604
var boundaryLineNumber = lineNumber;
611605

612-
await SkipLineAsync (false, cancellationToken).ConfigureAwait (false);
606+
SkipBoundaryMarker (endBoundary: true);
613607

614608
await OnMultipartEndBoundaryAsync (marker, boundaryOffset, GetOffset (inputIndex), boundaryLineNumber, cancellationToken).ConfigureAwait (false);
615609

MimeKit/MimeReader.cs

+12-15
Original file line numberDiff line numberDiff line change
@@ -1756,14 +1756,22 @@ unsafe void StepHeaders (byte* inbuf, CancellationToken cancellationToken)
17561756
OnHeadersEnd (headerBlockBegin, headersBeginLineNumber, headerBlockEnd, lineNumber, cancellationToken);
17571757
}
17581758

1759-
unsafe bool InnerSkipLine (byte* inbuf, bool consumeNewLine)
1759+
unsafe bool SkipBoundaryMarker (byte* inbuf, bool endBoundary)
17601760
{
1761+
// Don't consume the newline sequence for end boundaries (those are part of the epilogue).
1762+
bool consumeNewLine = !endBoundary;
17611763
byte* inptr = inbuf + inputIndex;
17621764
byte* inend = inbuf + inputEnd;
17631765

17641766
*inend = (byte) '\n';
17651767

1766-
// TODO: unroll this loop?
1768+
// skip over the boundary marker
1769+
if (endBoundary)
1770+
inptr += currentBoundary.FinalLength;
1771+
else
1772+
inptr += currentBoundary.Length;
1773+
1774+
// skip over any trailing whitespace
17671775
while (*inptr != (byte) '\n')
17681776
inptr++;
17691777

@@ -1785,17 +1793,6 @@ unsafe bool InnerSkipLine (byte* inbuf, bool consumeNewLine)
17851793
return false;
17861794
}
17871795

1788-
unsafe bool SkipLine (byte* inbuf, bool consumeNewLine, CancellationToken cancellationToken)
1789-
{
1790-
do {
1791-
if (InnerSkipLine (inbuf, consumeNewLine))
1792-
return true;
1793-
1794-
if (ReadAhead (ReadAheadSize, 1, cancellationToken) <= 0)
1795-
return false;
1796-
} while (true);
1797-
}
1798-
17991796
unsafe MimeParserState Step (byte* inbuf, CancellationToken cancellationToken)
18001797
{
18011798
switch (state) {
@@ -2233,7 +2230,7 @@ unsafe void MultipartScanSubparts (ContentType multipartContentType, byte* inbuf
22332230

22342231
do {
22352232
// skip over the boundary marker
2236-
if (!SkipLine (inbuf, true, cancellationToken)) {
2233+
if (!SkipBoundaryMarker (inbuf, endBoundary: false)) {
22372234
OnMultipartBoundary (multipartContentType.Boundary, boundaryOffset, GetOffset (inputIndex), lineNumber, cancellationToken);
22382235
boundary = BoundaryType.Eos;
22392236
return;
@@ -2359,7 +2356,7 @@ unsafe int ConstructMultipart (ContentType contentType, byte* inbuf, int depth,
23592356
var boundaryOffset = GetOffset (inputIndex);
23602357
var boundaryLineNumber = lineNumber;
23612358

2362-
SkipLine (inbuf, false, cancellationToken);
2359+
SkipBoundaryMarker (inbuf, endBoundary: true);
23632360

23642361
OnMultipartEndBoundary (marker, boundaryOffset, GetOffset (inputIndex), boundaryLineNumber, cancellationToken);
23652362

0 commit comments

Comments
 (0)