Merge topic 'dev/faster-parsers'

048be205 Help: Add release notes for the 'faster-parsers' topic
7c565d2f cmGeneratorExpression: Improve parsing in StripEmptyListElements
68eb1757 cmGeneratorExpressionLexer: Use a switch statement to parse
67253133 ExpandListArguments: Optimize the parser
This commit is contained in:
Brad King 2014-02-25 11:18:14 -05:00 committed by CMake Topic Stage
commit 958cd84431
4 changed files with 69 additions and 71 deletions

View File

@ -0,0 +1,6 @@
faster-parsers
--------------
* The :manual:`cmake-language(7)` internal implementation of generator
expression and list expansion parsers have been optimized and shows
non-trivial speedup on large projects.

View File

@ -157,17 +157,24 @@ cmCompiledGeneratorExpression::~cmCompiledGeneratorExpression()
std::string cmGeneratorExpression::StripEmptyListElements(
const std::string &input)
{
if (input.find(';') == input.npos)
{
return input;
}
std::string result;
result.reserve(input.size());
const char *c = input.c_str();
const char *last = c;
bool skipSemiColons = true;
for ( ; *c; ++c)
{
if(c[0] == ';')
if(*c == ';')
{
if(skipSemiColons)
{
continue;
result.append(last, c - last);
last = c + 1;
}
skipSemiColons = true;
}
@ -175,8 +182,8 @@ std::string cmGeneratorExpression::StripEmptyListElements(
{
skipSemiColons = false;
}
result += *c;
}
result.append(last);
if (!result.empty() && *(result.end() - 1) == ';')
{

View File

@ -42,42 +42,42 @@ cmGeneratorExpressionLexer::Tokenize(const char *input)
const char *upto = c;
for ( ; *c; ++c)
{
if(c[0] == '$' && c[1] == '<')
{
InsertText(upto, c, result);
upto = c;
result.push_back(cmGeneratorExpressionToken(
cmGeneratorExpressionToken::BeginExpression, upto, 2));
upto = c + 2;
++c;
SawBeginExpression = true;
}
else if(c[0] == '>')
{
InsertText(upto, c, result);
upto = c;
result.push_back(cmGeneratorExpressionToken(
cmGeneratorExpressionToken::EndExpression, upto, 1));
upto = c + 1;
SawGeneratorExpression = SawBeginExpression;
}
else if(c[0] == ':')
{
InsertText(upto, c, result);
upto = c;
result.push_back(cmGeneratorExpressionToken(
cmGeneratorExpressionToken::ColonSeparator, upto, 1));
upto = c + 1;
}
else if(c[0] == ',')
{
InsertText(upto, c, result);
upto = c;
result.push_back(cmGeneratorExpressionToken(
cmGeneratorExpressionToken::CommaSeparator, upto, 1));
upto = c + 1;
}
switch(*c)
{
case '$':
if(c[1] == '<')
{
InsertText(upto, c, result);
result.push_back(cmGeneratorExpressionToken(
cmGeneratorExpressionToken::BeginExpression, c, 2));
upto = c + 2;
++c;
SawBeginExpression = true;
}
break;
case '>':
InsertText(upto, c, result);
result.push_back(cmGeneratorExpressionToken(
cmGeneratorExpressionToken::EndExpression, c, 1));
upto = c + 1;
SawGeneratorExpression = SawBeginExpression;
break;
case ':':
InsertText(upto, c, result);
result.push_back(cmGeneratorExpressionToken(
cmGeneratorExpressionToken::ColonSeparator, c, 1));
upto = c + 1;
break;
case ',':
InsertText(upto, c, result);
result.push_back(cmGeneratorExpressionToken(
cmGeneratorExpressionToken::CommaSeparator, c, 1));
upto = c + 1;
break;
default:
break;
}
}
InsertText(upto, c, result);

View File

@ -1044,7 +1044,7 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
bool emptyArgs)
{
// If argument is empty, it is an empty list.
if(arg.length() == 0 && !emptyArgs)
if(!emptyArgs && arg.empty())
{
return;
}
@ -1054,10 +1054,11 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
newargs.push_back(arg);
return;
}
std::vector<char> newArgVec;
std::string newArg;
const char *last = arg.c_str();
// Break the string at non-escaped semicolons not nested in [].
int squareNesting = 0;
for(const char* c = arg.c_str(); *c; ++c)
for(const char* c = last; *c; ++c)
{
switch(*c)
{
@ -1065,34 +1066,21 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
{
// We only want to allow escaping of semicolons. Other
// escapes should not be processed here.
++c;
if(*c == ';')
const char* next = c + 1;
if(*next == ';')
{
newArgVec.push_back(*c);
}
else
{
newArgVec.push_back('\\');
if(*c)
{
newArgVec.push_back(*c);
}
else
{
// Terminate the loop properly.
--c;
}
newArg.append(last, c - last);
// Skip over the escape character
last = c = next;
}
} break;
case '[':
{
++squareNesting;
newArgVec.push_back(*c);
} break;
case ']':
{
--squareNesting;
newArgVec.push_back(*c);
} break;
case ';':
{
@ -1100,31 +1088,28 @@ void cmSystemTools::ExpandListArgument(const std::string& arg,
// brackets.
if(squareNesting == 0)
{
if ( newArgVec.size() || emptyArgs )
newArg.append(last, c - last);
// Skip over the semicolon
last = c + 1;
if ( !newArg.empty() || emptyArgs )
{
// Add the last argument if the string is not empty.
newArgVec.push_back(0);
newargs.push_back(&*newArgVec.begin());
newArgVec.clear();
newargs.push_back(newArg);
newArg = "";
}
}
else
{
newArgVec.push_back(*c);
}
} break;
default:
{
// Just append this character.
newArgVec.push_back(*c);
} break;
}
}
if ( newArgVec.size() || emptyArgs )
newArg.append(last);
if ( !newArg.empty() || emptyArgs )
{
// Add the last argument if the string is not empty.
newArgVec.push_back(0);
newargs.push_back(&*newArgVec.begin());
newargs.push_back(newArg);
}
}