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 Nibbler::getQuoted (char c, std::string& result)
{ {
bool inquote = false;
bool inescape = false;
char previous = 0;
char current = 0;
result = ""; result = "";
if (_cursor >= _length || if (_cursor >= _length ||
@@ -194,42 +193,52 @@ bool Nibbler::getQuoted (char c, std::string& result)
return false; 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; // Empty quote
previous = current; _cursor += 2; // Skip both quote chars
continue; 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; // Toggle flag for each further backslash encountered.
} is_escaped_quote = is_escaped_quote ? false : true;
else --j;
{
_cursor = i + 1;
return true;
}
}
else
{
if (previous)
{
result += previous;
previous = 0;
} }
result += current; if (is_escaped_quote)
inescape = false; {
// 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; return false;
} }