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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user