optimize low-level pro reader code

avoid qstring functions. instead, use preallocated strings and pointers.
now the majority of the parsing time is spent in qt (qfile and qtextcodec).
This commit is contained in:
Oswald Buddenhagen
2009-07-15 09:58:56 +02:00
parent e917eeacb9
commit 4c561414a6

View File

@@ -140,7 +140,7 @@ public:
ProBlock *currentBlock(); ProBlock *currentBlock();
void updateItem(); void updateItem();
bool parseLine(const QString &line); bool parseLine(const QString &line);
void insertVariable(const QString &line, int *i); void insertVariable(const ushort **pCur, const ushort *end);
void insertOperator(const char op); void insertOperator(const char op);
void insertComment(const QString &comment); void insertComment(const QString &comment);
void enterScope(bool multiLine); void enterScope(bool multiLine);
@@ -153,11 +153,14 @@ public:
ProItem *m_commentItem; ProItem *m_commentItem;
QString m_proitem; QString m_proitem;
QString m_pendingComment; QString m_pendingComment;
ushort *m_proitemPtr;
bool m_syntaxError; bool m_syntaxError;
bool m_contNextLine; bool m_contNextLine;
bool m_inQuote; bool m_inQuote;
int m_parens; int m_parens;
enum StrState { NotStarted, Started, PutSpace };
/////////////// Evaluating pro file contents /////////////// Evaluating pro file contents
// implementation of AbstractProItemVisitor // implementation of AbstractProItemVisitor
@@ -304,32 +307,36 @@ bool ProFileEvaluator::Private::read(ProFile *pro, QTextStream *ts)
return true; return true;
} }
bool ProFileEvaluator::Private::parseLine(const QString &line0) bool ProFileEvaluator::Private::parseLine(const QString &line)
{ {
if (m_blockstack.isEmpty()) if (m_blockstack.isEmpty())
return false; return false;
const ushort *cur = (const ushort *)line.unicode(),
*end = cur + line.length();
int parens = m_parens; int parens = m_parens;
bool inQuote = m_inQuote; bool inQuote = m_inQuote;
bool escaped = false; bool escaped = false;
QString line = line0.simplified();
for (int i = 0; !m_syntaxError && i < line.length(); ++i) { m_proitem.reserve(line.length());
ushort c = line.at(i).unicode(); m_proitemPtr = (ushort *)m_proitem.unicode();
nextItem:
ushort *ptr = m_proitemPtr;
StrState sts = NotStarted;
while (cur < end) {
ushort c = *cur++;
if (c == '#') { // Yep - no escaping possible if (c == '#') { // Yep - no escaping possible
insertComment(line.mid(i + 1)); m_proitemPtr = ptr;
escaped = m_contNextLine; insertComment(line.right(end - cur).simplified());
break; goto done;
} }
if (!escaped) { if (!escaped) {
if (c == '\\') { if (c == '\\') {
escaped = true; escaped = true;
m_proitem += c; goto putch;
continue;
} else if (c == '"') { } else if (c == '"') {
inQuote = !inQuote; inQuote = !inQuote;
m_proitem += c; goto putch;
continue;
} }
} else { } else {
escaped = false; escaped = false;
@@ -341,52 +348,70 @@ bool ProFileEvaluator::Private::parseLine(const QString &line0)
--parens; --parens;
} else if (!parens) { } else if (!parens) {
if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) { if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) {
if (c == ' ') if (c == ' ' || c == '\t') {
m_proitemPtr = ptr;
updateItem(); updateItem();
else goto nextItem;
m_proitem += c;
continue;
} }
} else {
if (c == ':') { if (c == ':') {
m_proitemPtr = ptr;
enterScope(false); enterScope(false);
continue; goto nextItem;
} }
if (c == '{') { if (c == '{') {
m_proitemPtr = ptr;
enterScope(true); enterScope(true);
continue; goto nextItem;
} }
if (c == '}') { if (c == '}') {
m_proitemPtr = ptr;
leaveScope(); leaveScope();
continue; if (m_syntaxError)
goto done1;
goto nextItem;
} }
if (c == '=') { if (c == '=') {
insertVariable(line, &i); m_proitemPtr = ptr;
continue; insertVariable(&cur, end);
goto nextItem;
} }
if (c == '|' || c == '!') { if (c == '|' || c == '!') {
m_proitemPtr = ptr;
insertOperator(c); insertOperator(c);
continue; goto nextItem;
}
} }
} }
} }
m_proitem += c; if (c == ' ' || c == '\t') {
if (sts == Started)
sts = PutSpace;
} else {
putch:
if (sts == PutSpace)
*ptr++ = ' ';
*ptr++ = c;
sts = Started;
} }
}
m_proitemPtr = ptr;
done1:
m_contNextLine = escaped;
done:
m_inQuote = inQuote; m_inQuote = inQuote;
m_parens = parens; m_parens = parens;
m_contNextLine = escaped; if (m_syntaxError)
return false;
if (escaped) { if (escaped) {
m_proitem.chop(1); --m_proitemPtr;
updateItem(); updateItem();
return true;
} else { } else {
if (!m_syntaxError) {
updateItem(); updateItem();
finalizeBlock(); finalizeBlock();
}
return true; return true;
}
return false;
}
} }
void ProFileEvaluator::Private::finalizeBlock() void ProFileEvaluator::Private::finalizeBlock()
@@ -401,37 +426,44 @@ void ProFileEvaluator::Private::finalizeBlock()
} }
} }
void ProFileEvaluator::Private::insertVariable(const QString &line, int *i) void ProFileEvaluator::Private::insertVariable(const ushort **pCur, const ushort *end)
{ {
ProVariable::VariableOperator opkind; ProVariable::VariableOperator opkind;
ushort *uc = (ushort *)m_proitem.unicode();
ushort *ptr = m_proitemPtr;
if (m_proitem.isEmpty()) // Line starting with '=', like a conflict marker if (ptr == uc) // Line starting with '=', like a conflict marker
return; return;
switch (m_proitem.at(m_proitem.length() - 1).unicode()) { switch (*(ptr - 1)) {
case '+': case '+':
m_proitem.chop(1); --ptr;
opkind = ProVariable::AddOperator; opkind = ProVariable::AddOperator;
break; break;
case '-': case '-':
m_proitem.chop(1); --ptr;
opkind = ProVariable::RemoveOperator; opkind = ProVariable::RemoveOperator;
break; break;
case '*': case '*':
m_proitem.chop(1); --ptr;
opkind = ProVariable::UniqueAddOperator; opkind = ProVariable::UniqueAddOperator;
break; break;
case '~': case '~':
m_proitem.chop(1); --ptr;
opkind = ProVariable::ReplaceOperator; opkind = ProVariable::ReplaceOperator;
break; break;
default: default:
opkind = ProVariable::SetOperator; opkind = ProVariable::SetOperator;
} }
while (ptr != uc && *(ptr - 1) == ' ')
--ptr;
m_proitem.resize(ptr - uc);
QString proVar = m_proitem;
proVar.detach();
ProBlock *block = m_blockstack.top(); ProBlock *block = m_blockstack.top();
m_proitem = m_proitem.trimmed(); ProVariable *variable = new ProVariable(proVar, block);
ProVariable *variable = new ProVariable(m_proitem, block);
variable->setLineNumber(m_lineNo); variable->setLineNumber(m_lineNo);
variable->setVariableOperator(opkind); variable->setVariableOperator(opkind);
block->appendItem(variable); block->appendItem(variable);
@@ -443,26 +475,31 @@ void ProFileEvaluator::Private::insertVariable(const QString &line, int *i)
} }
m_commentItem = variable; m_commentItem = variable;
m_proitem.clear();
if (opkind == ProVariable::ReplaceOperator) { if (opkind == ProVariable::ReplaceOperator) {
// skip util end of line or comment // skip util end of line or comment
while (1) { StrState sts = NotStarted;
++(*i); ptr = uc;
const ushort *cur = *pCur;
// end of line? while (cur < end) {
if (*i >= line.count()) ushort c = *cur;
if (c == '#') // comment?
break; break;
++cur;
// comment? if (c == ' ' || c == '\t') {
if (line.at(*i).unicode() == '#') { if (sts == Started)
--(*i); sts = PutSpace;
break; } else {
if (sts == PutSpace)
*ptr++ = ' ';
*ptr++ = c;
sts = Started;
} }
m_proitem += line.at(*i);
} }
m_proitem = m_proitem.trimmed(); *pCur = cur;
m_proitemPtr = ptr;
} else {
m_proitemPtr = uc;
} }
} }
@@ -563,22 +600,27 @@ ProBlock *ProFileEvaluator::Private::currentBlock()
void ProFileEvaluator::Private::updateItem() void ProFileEvaluator::Private::updateItem()
{ {
m_proitem = m_proitem.trimmed(); ushort *uc = (ushort *)m_proitem.unicode();
if (m_proitem.isEmpty()) ushort *ptr = m_proitemPtr;
if (ptr == uc)
return; return;
m_proitem.resize(ptr - uc);
m_proitemPtr = uc;
QString proItem = m_proitem;
proItem.detach();
ProBlock *block = currentBlock(); ProBlock *block = currentBlock();
if (block->blockKind() & ProBlock::VariableKind) { if (block->blockKind() & ProBlock::VariableKind) {
m_commentItem = new ProValue(m_proitem, static_cast<ProVariable*>(block)); m_commentItem = new ProValue(proItem, static_cast<ProVariable*>(block));
} else if (m_proitem.endsWith(QLatin1Char(')'))) { } else if (proItem.endsWith(QLatin1Char(')'))) {
m_commentItem = new ProFunction(m_proitem); m_commentItem = new ProFunction(proItem);
} else { } else {
m_commentItem = new ProCondition(m_proitem); m_commentItem = new ProCondition(proItem);
} }
m_commentItem->setLineNumber(m_lineNo); m_commentItem->setLineNumber(m_lineNo);
block->appendItem(m_commentItem); block->appendItem(m_commentItem);
m_proitem.clear();
} }