Nibbler: Improve getQuoted() performance

Improves "load" time for all performance tests that load data by ~20%.
 - "next"   down 15% total
 - "list"   down  7% total
 - "all"    down  3% total
 - "add"    down 15% total
 - "export" down  8% total
 - "import" down  6% total
This commit is contained in:
Wilhelm Schuermann 2015-11-12 16:14:29 +01:00
parent 96ca7eb5f2
commit 77283241a9

View file

@ -180,12 +180,11 @@ bool Nibbler::getN (const int quantity, std::string& result)
}
////////////////////////////////////////////////////////////////////////////////
// Gets quote content: "foobar" -> foobar (for c = '"')
// Handles escaped quotes: "foo\"bar" -> foo\"bar (for c = '"')
// Returns false if first character is not c, or if there is no closing c
bool Nibbler::getQuoted (char c, std::string& result)
{
bool inquote = false;
bool inescape = false;
char previous = 0;
char current = 0;
result = "";
if (_cursor >= _length ||
@ -194,42 +193,52 @@ bool Nibbler::getQuoted (char c, std::string& result)
return false;
}
for (auto i = _cursor; i < _length; ++i)
std::string::size_type start = _cursor + 1; // Skip first quote char
std::string::size_type i = start;
while (i < _length)
{
current = (*_input)[i];
i = (*_input).find (c, i);
if (current == '\\' && !inescape)
if (i == std::string::npos)
return false; // Unclosed quote
if (i == start)
{
inescape = true;
previous = current;
continue;
// Empty quote
_cursor += 2; // Skip both quote chars
return true;
}
if (current == c && !inescape)
if ((*_input)[i-1] == '\\')
{
if (!inquote)
// Check for escaped backslashes. Backtracking like this is not very
// efficient, but is only done in extreme corner cases.
auto j = i-2; // Start one character further left
bool is_escaped_quote = true;
while (j >= start && (*_input)[j] == '\\')
{
inquote = true;
}
else
{
_cursor = i + 1;
return true;
}
}
else
{
if (previous)
{
result += previous;
previous = 0;
// Toggle flag for each further backslash encountered.
is_escaped_quote = is_escaped_quote ? false : true;
--j;
}
result += current;
inescape = false;
if (is_escaped_quote)
{
// Keep searching
++i;
continue;
}
}
// None of the above applied, we must have found the closing quote char.
result.assign ((*_input), start, i - start);
_cursor = i + 1; // Skip closing quote char
return true;
}
// This should never be reached. We could throw here instead.
return false;
}