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

View File

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

View File

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