StdCompilerINIRead: Maintain line break cache for error msgs (#1310)

Deserializing proplists tries to read a boolean variable from the
representation in order to be backwards compatible to old (<6.0)
savegames. Newer savegames do not write this boolean, so StdCompiler
(correctly) throws an exception. This exception uses line numbers, which
StdCompiler used to obtain by scanning through the entire buffer. Having
to scan through the entire buffer for every serialized proplist is
ridiculously slow (and the data isn't used anyway in this instance).
Since line information is still valuable outside of proplist
deserialization, replace the repeated SGetLine calls with an on-demand
cache.
This reduces load times of a 14 MB Game.txt from slightly over 3 minutes
to 7 seconds on my computer.
stable-6.1
Nicolas Hake 2015-05-10 20:09:51 +02:00
parent 5deb01fff9
commit e2a42de2f2
2 changed files with 39 additions and 4 deletions

View File

@ -650,14 +650,46 @@ void StdCompilerINIRead::Raw(void *pData, size_t iSize, RawCompileType eType)
MemCopy(Buf.getData(), pData, iSize);
}
uint32_t StdCompilerINIRead::getLineNumberOfPos(const char *pos) const
{
// Figure out quickly whether we already know which line this is
auto entry = std::lower_bound(lineBreaks.begin(), lineBreaks.end(), pos);
if (entry != lineBreaks.end())
{
return std::distance(lineBreaks.begin(), entry) + 1;
}
// Otherwise search through the buffer until we find out, filling the
// cache in the process
const char *cursor = Buf.getData();
if (!lineBreaks.empty())
cursor = *(lineBreaks.end() - 1) + 1;
for (;;)
{
if (*cursor == '\0' || *cursor == '\n')
{
lineBreaks.push_back(cursor);
// If we're at the end of the file or have found the line break
// past the requested position, we're done for now
if (*cursor == '\0' || pos < cursor)
{
break;
}
}
++cursor;
}
return std::distance(lineBreaks.begin(),
std::lower_bound(lineBreaks.begin(), lineBreaks.end(), pos)) + 1;
}
StdStrBuf StdCompilerINIRead::getPosition() const
{
if (pPos)
return FormatString("line %d", SGetLine(Buf.getData(), pPos));
return FormatString("line %d", getLineNumberOfPos(pPos));
else if (iDepth == iRealDepth)
return FormatString(pName->Section ? "section \"%s\", after line %d" : "value \"%s\", line %d", pName->Name.getData(), SGetLine(Buf.getData(), pName->Pos));
return FormatString(pName->Section ? "section \"%s\", after line %d" : "value \"%s\", line %d", pName->Name.getData(), getLineNumberOfPos(pName->Pos));
else if (iRealDepth)
return FormatString("missing value/section \"%s\" inside section \"%s\" (line %d)", NotFoundName.getData(), pName->Name.getData(), SGetLine(Buf.getData(), pName->Pos));
return FormatString("missing value/section \"%s\" inside section \"%s\" (line %d)", NotFoundName.getData(), pName->Name.getData(), getLineNumberOfPos(pName->Pos));
else
return FormatString("missing value/section \"%s\"", NotFoundName.getData());
}

View File

@ -628,7 +628,7 @@ public:
// Input
typedef StdStrBuf InT;
void setInput(const InT &In) { Buf.Ref(In); }
void setInput(const InT &In) { Buf.Ref(In); lineBreaks.clear(); }
// Properties
virtual bool isCompiler() { return true; }
@ -728,6 +728,9 @@ protected:
void notFound(const char *szWhat);
private:
uint32_t getLineNumberOfPos(const char *pos) const;
mutable std::vector<const char *> lineBreaks;
};
void StdCompilerWarnCallback(void *pData, const char *szPosition, const char *szError);