optimize assignments: record number of literals

that way the result vector can be pre-allocated - which gives zero
resizes if no expansions are in the expression.
for the joined argument lists of built-in functions, pre-allocate a
fixed 5 elements, which covers all cases and more.
the argument lists of user-defined functions are not pre-allocated
yet.
This commit is contained in:
Oswald Buddenhagen
2010-05-31 21:07:14 +02:00
parent a1fa00d2e7
commit 033a148b43
2 changed files with 28 additions and 10 deletions

View File

@@ -199,6 +199,8 @@ public:
struct ParseCtx { struct ParseCtx {
int parens; // Nesting of non-functional parentheses int parens; // Nesting of non-functional parentheses
int argc; // Number of arguments in current function call int argc; // Number of arguments in current function call
int litCount; // Number of literals in current expression
int expCount; // Number of expansions in current expression
Context context; Context context;
ushort quote; // Enclosing quote type ushort quote; // Enclosing quote type
ushort terminator; // '}' if replace function call is braced, ':' if test function ushort terminator; // '}' if replace function call is braced, ':' if test function
@@ -266,7 +268,7 @@ public:
static ProStringList split_value_list(const QString &vals); static ProStringList split_value_list(const QString &vals);
bool isActiveConfig(const QString &config, bool regex = false); bool isActiveConfig(const QString &config, bool regex = false);
ProStringList expandVariableReferences(const ProString &value, int *pos = 0, bool joined = false); ProStringList expandVariableReferences(const ProString &value, int *pos = 0, bool joined = false);
ProStringList expandVariableReferences(const ushort *&tokPtr, bool joined = false); ProStringList expandVariableReferences(const ushort *&tokPtr, int sizeHint = 0, bool joined = false);
ProStringList evaluateExpandFunction(const ProString &function, const ProString &arguments); ProStringList evaluateExpandFunction(const ProString &function, const ProString &arguments);
ProStringList evaluateExpandFunction(const ProString &function, const ushort *&tokPtr); ProStringList evaluateExpandFunction(const ProString &function, const ushort *&tokPtr);
ProStringList evaluateExpandFunction(const ProString &function, const ProStringList &args); ProStringList evaluateExpandFunction(const ProString &function, const ProStringList &args);
@@ -681,6 +683,8 @@ bool ProFileEvaluator::Private::readInternal(QString *out, const QString &in)
Context context = CtxTest; Context context = CtxTest;
int parens = 0; int parens = 0;
int argc = 0; int argc = 0;
int litCount = 0;
int expCount = 0;
bool inError = false; bool inError = false;
bool putSpace = false; // Only ever true inside quoted string bool putSpace = false; // Only ever true inside quoted string
bool lineMarked = true; // For in-expression markers bool lineMarked = true; // For in-expression markers
@@ -714,6 +718,7 @@ bool ProFileEvaluator::Private::readInternal(QString *out, const QString &in)
xprPtr[-1] = tlen; \ xprPtr[-1] = tlen; \
if (setSep) \ if (setSep) \
needSep = TokNewStr; \ needSep = TokNewStr; \
litCount++; \
} else { \ } else { \
ptr -= 2; \ ptr -= 2; \
if (setSep && ptr != ((context == CtxValue) ? tokPtr : buf)) \ if (setSep && ptr != ((context == CtxValue) ? tokPtr : buf)) \
@@ -822,6 +827,7 @@ bool ProFileEvaluator::Private::readInternal(QString *out, const QString &in)
xprPtr[-2] = TokLiteral | needSep; xprPtr[-2] = TokLiteral | needSep;
xprPtr[-1] = tlen; xprPtr[-1] = tlen;
needSep = 0; needSep = 0;
litCount++;
} else { } else {
ptr -= 2; ptr -= 2;
} }
@@ -871,6 +877,7 @@ bool ProFileEvaluator::Private::readInternal(QString *out, const QString &in)
tok |= TokQuoted; tok |= TokQuoted;
tok |= needSep; tok |= needSep;
needSep = 0; needSep = 0;
expCount++;
tlen = ptr - xprPtr; tlen = ptr - xprPtr;
if (rtok == TokVariable) { if (rtok == TokVariable) {
xprPtr[-4] = tok; xprPtr[-4] = tok;
@@ -892,6 +899,8 @@ bool ProFileEvaluator::Private::readInternal(QString *out, const QString &in)
top.terminator = term; top.terminator = term;
top.context = context; top.context = context;
top.argc = argc; top.argc = argc;
top.litCount = litCount;
top.expCount = expCount;
} }
parens = 0; parens = 0;
quote = 0; quote = 0;
@@ -962,6 +971,8 @@ bool ProFileEvaluator::Private::readInternal(QString *out, const QString &in)
term = top.terminator; term = top.terminator;
context = top.context; context = top.context;
argc = top.argc; argc = top.argc;
litCount = top.litCount;
expCount = top.expCount;
xprStack.resize(xprStack.size() - 1); xprStack.resize(xprStack.size() - 1);
} }
if (term == ':') { if (term == ':') {
@@ -1070,7 +1081,8 @@ bool ProFileEvaluator::Private::readInternal(QString *out, const QString &in)
putBlock(tokPtr, buf, tlen); putBlock(tokPtr, buf, tlen);
putTok(tokPtr, tok); putTok(tokPtr, tok);
context = CtxValue; context = CtxValue;
ptr = tokPtr; ptr = ++tokPtr;
litCount = expCount = 0;
needSep = 0; needSep = 0;
goto nextToken; goto nextToken;
} }
@@ -1109,6 +1121,7 @@ bool ProFileEvaluator::Private::readInternal(QString *out, const QString &in)
return false; return false;
} }
if (context == CtxValue) { if (context == CtxValue) {
tokPtr[-1] = litCount ? litCount + expCount : 0;
tokPtr = ptr; tokPtr = ptr;
putTok(tokPtr, TokValueTerminator); putTok(tokPtr, TokValueTerminator);
} else { } else {
@@ -1837,7 +1850,7 @@ ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProLoop(
int index = 0; int index = 0;
ProString variable; ProString variable;
ProStringList oldVarVal; ProStringList oldVarVal;
ProString it_list = expandVariableReferences(exprPtr, true).at(0); ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0);
if (_variable.isEmpty()) { if (_variable.isEmpty()) {
if (it_list != statics.strever) { if (it_list != statics.strever) {
logMessage(format("Invalid loop expression.")); logMessage(format("Invalid loop expression."));
@@ -1919,6 +1932,8 @@ ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::visitProLoop(
void ProFileEvaluator::Private::visitProVariable( void ProFileEvaluator::Private::visitProVariable(
ushort tok, const ProStringList &curr, const ushort *&tokPtr) ushort tok, const ProStringList &curr, const ushort *&tokPtr)
{ {
int sizeHint = *tokPtr++;
if (curr.size() != 1) { if (curr.size() != 1) {
skipExpression(tokPtr); skipExpression(tokPtr);
logMessage(format("Left hand side of assignment must expand to exactly one word.")); logMessage(format("Left hand side of assignment must expand to exactly one word."));
@@ -1929,7 +1944,7 @@ void ProFileEvaluator::Private::visitProVariable(
if (tok == TokReplace) { // ~= if (tok == TokReplace) { // ~=
// DEFINES ~= s/a/b/?[gqi] // DEFINES ~= s/a/b/?[gqi]
const ProStringList &varVal = expandVariableReferences(tokPtr, true); const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true);
const QString &val = varVal.at(0).toQString(m_tmp1); const QString &val = varVal.at(0).toQString(m_tmp1);
if (val.length() < 4 || val.at(0) != QLatin1Char('s')) { if (val.length() < 4 || val.at(0) != QLatin1Char('s')) {
logMessage(format("the ~= operator can handle only the s/// function.")); logMessage(format("the ~= operator can handle only the s/// function."));
@@ -1962,7 +1977,7 @@ void ProFileEvaluator::Private::visitProVariable(
replaceInList(&m_filevaluemap[currentProFile()][varName], regexp, replace, global, m_tmp2); replaceInList(&m_filevaluemap[currentProFile()][varName], regexp, replace, global, m_tmp2);
} }
} else { } else {
ProStringList varVal = expandVariableReferences(tokPtr); ProStringList varVal = expandVariableReferences(tokPtr, sizeHint);
switch (tok) { switch (tok) {
default: // whatever - cannot happen default: // whatever - cannot happen
case TokAssign: // = case TokAssign: // =
@@ -2641,9 +2656,10 @@ bool ProFileEvaluator::Private::isActiveConfig(const QString &config, bool regex
} }
ProStringList ProFileEvaluator::Private::expandVariableReferences( ProStringList ProFileEvaluator::Private::expandVariableReferences(
const ushort *&tokPtr, bool joined) const ushort *&tokPtr, int sizeHint, bool joined)
{ {
ProStringList ret; ProStringList ret;
ret.reserve(sizeHint);
forever { forever {
evaluateExpression(tokPtr, &ret, joined); evaluateExpression(tokPtr, &ret, joined);
switch (*tokPtr) { switch (*tokPtr) {
@@ -2761,7 +2777,7 @@ ProStringList ProFileEvaluator::Private::evaluateExpandFunction(
return evaluateFunction(*it, prepareFunctionArgs(tokPtr), 0); return evaluateFunction(*it, prepareFunctionArgs(tokPtr), 0);
//why don't the builtin functions just use args_list? --Sam //why don't the builtin functions just use args_list? --Sam
return evaluateExpandFunction(func, expandVariableReferences(tokPtr, true)); return evaluateExpandFunction(func, expandVariableReferences(tokPtr, 5, true));
} }
ProStringList ProFileEvaluator::Private::evaluateExpandFunction( ProStringList ProFileEvaluator::Private::evaluateExpandFunction(
@@ -3179,7 +3195,7 @@ ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateCondit
return evaluateBoolFunction(*it, prepareFunctionArgs(tokPtr), function); return evaluateBoolFunction(*it, prepareFunctionArgs(tokPtr), function);
//why don't the builtin functions just use args_list? --Sam //why don't the builtin functions just use args_list? --Sam
return evaluateConditionalFunction(function, expandVariableReferences(tokPtr, true)); return evaluateConditionalFunction(function, expandVariableReferences(tokPtr, 5, true));
} }
ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction( ProFileEvaluator::Private::VisitReturn ProFileEvaluator::Private::evaluateConditionalFunction(

View File

@@ -137,6 +137,8 @@ static const ushort *skipToken(ushort tok, const ushort *&tokPtr, int &lineNo)
case TokAppendUnique: case TokAppendUnique:
case TokRemove: case TokRemove:
case TokReplace: case TokReplace:
tokPtr++;
// fallthrough
case TokTestCall: case TokTestCall:
skipExpression(tokPtr, lineNo); skipExpression(tokPtr, lineNo);
break; break;
@@ -206,7 +208,7 @@ void ProWriter::addFiles(ProFile *profile, QStringList *lines,
lines->insert(lineNo, added); lines->insert(lineNo, added);
return; return;
} }
skipExpression(tokPtr, lineNo); skipExpression(++tokPtr, lineNo);
} else { } else {
lastXpr = skipToken(tok, tokPtr, lineNo); lastXpr = skipToken(tok, tokPtr, lineNo);
} }
@@ -236,7 +238,7 @@ static void findProVariables(const ushort *tokPtr, const QStringList &vars,
} else if (tok == TokAssign || tok == TokAppend || tok == TokAppendUnique) { } else if (tok == TokAssign || tok == TokAppend || tok == TokAppendUnique) {
if (getLiteral(lastXpr, tokPtr - 1, tmp) && vars.contains(tmp)) if (getLiteral(lastXpr, tokPtr - 1, tmp) && vars.contains(tmp))
*proVars << lineNo; *proVars << lineNo;
skipExpression(tokPtr, lineNo); skipExpression(++tokPtr, lineNo);
} else { } else {
lastXpr = skipToken(tok, tokPtr, lineNo); lastXpr = skipToken(tok, tokPtr, lineNo);
} }