replaced ReadByte with 64kb buffer in parser

This commit is contained in:
2026-09-14 23:09:16 +02:00
parent f726597401
commit f1aca261ae
+65 -59
View File
@@ -1,4 +1,4 @@
global using System;
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Text;
@@ -80,69 +80,75 @@ public class SaveParserEU4
return true;
}
while (_saveFile.CanRead)
// Reading the save one byte at a time through Stream.ReadByte() costs a virtual call
// per byte, which dominated the parsing time. Bytes are pulled into this buffer
// instead, so the stream is touched once per 64 KB and the inner loop reads an array.
byte[] buffer = new byte[64 * 1024];
int bufferLength;
while ((bufferLength = _saveFile.Read(buffer, 0, buffer.Length)) > 0)
{
int c = _saveFile.ReadByte();
column++;
switch (c)
for (int i = 0; i < bufferLength; i++)
{
case -1:
if (TryCompleteStringToken())
yield return strToken;
_stringBuilderPool.Return(strb);
yield break;
case '\"':
isQuoteOpen = !isQuoteOpen;
isStrInQuotes = true;
break;
case ' ':
case '\t':
case '\r':
if (TryCompleteStringToken())
yield return strToken;
break;
case '\n':
if (TryCompleteStringToken())
yield return strToken;
line++;
column = 0;
break;
case '=':
if (TryCompleteStringToken())
yield return strToken;
yield return new Token
{
type = TokenType.Equals,
line = line, column = (short)column
};
break;
case '{':
if (TryCompleteStringToken())
yield return strToken;
yield return new Token
{
type = TokenType.BracketOpen,
line = line, column = (short)column
};
break;
case '}':
if (TryCompleteStringToken())
yield return strToken;
yield return new Token
{
type = TokenType.BracketClose,
line = line, column = (short)column
};
break;
default:
// Skip control characters, which are invisible and causing frontend bugs.
// I dont know why there are so many of them in strings.
if (c >= 0x20)
strb.Append((char)c);
break;
int c = buffer[i];
column++;
switch (c)
{
case '\"':
isQuoteOpen = !isQuoteOpen;
isStrInQuotes = true;
break;
case ' ':
case '\t':
case '\r':
if (TryCompleteStringToken())
yield return strToken;
break;
case '\n':
if (TryCompleteStringToken())
yield return strToken;
line++;
column = 0;
break;
case '=':
if (TryCompleteStringToken())
yield return strToken;
yield return new Token
{
type = TokenType.Equals,
line = line, column = (short)column
};
break;
case '{':
if (TryCompleteStringToken())
yield return strToken;
yield return new Token
{
type = TokenType.BracketOpen,
line = line, column = (short)column
};
break;
case '}':
if (TryCompleteStringToken())
yield return strToken;
yield return new Token
{
type = TokenType.BracketClose,
line = line, column = (short)column
};
break;
default:
// Skip control characters, which are invisible and causing frontend bugs.
// I dont know why there are so many of them in strings.
if (c >= 0x20)
strb.Append((char)c);
break;
}
}
}
// end of file: the last token may still be unterminated
if (TryCompleteStringToken())
yield return strToken;
_stringBuilderPool.Return(strb);
}