forked from Mirrors/openclonk
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
parent
5deb01fff9
commit
e2a42de2f2
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue